From d487aa32905a0150cb8afc82d74595219af0be0c Mon Sep 17 00:00:00 2001 From: zeman Date: Tue, 21 Aug 2018 00:44:14 +0200 Subject: [PATCH 01/10] added missing CHANGELOG entry for PR #2048 --- package/CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/package/CHANGELOG b/package/CHANGELOG index 946e8458de3..b883cb6fff2 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -80,6 +80,8 @@ Enhancements * Added dihedrals.py with Dihedral, Ramachandran, and Janin classes to analysis module (PR #1997, PR #2033) * Added the analysis.data module for reference data used in analysis (PR #2033) + * Most functions in `MDanalysis.lib.distances` previously only accepting + arrays of coordinates now also accept single coordinates as input (PR #2048) Fixes * rewind in the SingleFrameReader now reads the frame from the file (Issue #1929) @@ -117,6 +119,9 @@ Changes (Issue #1894) * removed unused function MDAnalysis.lb.mdamath.one_to_many_pointers() (issue #2010) + * Box input for functions in `MDAnalysis.lib.distances` is now consistently + enforced to be of the form ``[lx, ly, lz, alpha, beta, gamma]`` as required + by the docs (Issue #2046, PR #2048) Deprecations * almost all "save()", "save_results()", "save_table()" methods in From 6d9e3eac56538bcb79dd8a1e1c0a6489e45a3ca9 Mon Sep 17 00:00:00 2001 From: zeman Date: Tue, 21 Aug 2018 00:45:48 +0200 Subject: [PATCH 02/10] ensured `lib.distances.distance_array()` always returns an array --- package/MDAnalysis/lib/distances.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index 25d2822fd0f..3709d390e16 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -221,7 +221,7 @@ def _check_result_array(result, shape): return result @check_coords('reference', 'configuration', enforce_copy=False, - check_lengths_match=False) + reduce_result_if_single=False, check_lengths_match=False) def distance_array(reference, configuration, box=None, result=None, backend="serial"): """Calculate all distances between a reference set and another configuration. From bb55d16ac6a8a71dfca60933be3cf14a54b7a7e8 Mon Sep 17 00:00:00 2001 From: zeman Date: Mon, 3 Sep 2018 09:15:24 +0200 Subject: [PATCH 03/10] improved docstrings in lib/_augment.pyx --- package/MDAnalysis/lib/_augment.pyx | 683 ++++++++++++++-------------- 1 file changed, 341 insertions(+), 342 deletions(-) diff --git a/package/MDAnalysis/lib/_augment.pyx b/package/MDAnalysis/lib/_augment.pyx index a1f90631dfe..9e8fe263c76 100644 --- a/package/MDAnalysis/lib/_augment.pyx +++ b/package/MDAnalysis/lib/_augment.pyx @@ -1,342 +1,341 @@ -# -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; -*- -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 -# -# MDAnalysis --- https://www.mdanalysis.org -# Copyright (c) 2006-2017 The MDAnalysis Development Team and contributors -# (see the file AUTHORS for the full list of names) -# -# Released under the GNU Public Licence, v2 or any higher version -# -# Please cite your use of MDAnalysis in published work: -# -# R. J. Gowers, M. Linke, J. Barnoud, T. J. E. Reddy, M. N. Melo, S. L. Seyler, -# D. L. Dotson, J. Domanski, S. Buchoux, I. M. Kenney, and O. Beckstein. -# MDAnalysis: A Python package for the rapid analysis of molecular dynamics -# simulations. In S. Benthall and S. Rostrup editors, Proceedings of the 15th -# Python in Science Conference, pages 102-109, Austin, TX, 2016. SciPy. -# -# N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and O. Beckstein. -# MDAnalysis: A Toolkit for the Analysis of Molecular Dynamics Simulations. -# J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787 -# -# - -import cython -import numpy as np -from .mdamath import triclinic_vectors -cimport numpy as np -cimport _cutil -from _cutil cimport _dot ,_norm, _cross - -from libcpp.vector cimport vector - - -__all__ = ['augment_coordinates', 'undo_augment'] - - -@cython.boundscheck(False) -@cython.wraparound(False) -def augment_coordinates(float[:, ::1] coordinates, float[:] box, float r): - r"""Calculates the relevant images of particles which are within a - distance 'r' from the box walls - - The algorithm works by generating explicit periodic images of - interior atoms residing close to any of the six box walls. - The steps involved in generating images involves - evaluation of reciprocal vectors for the given box vectors - followed by calculation of projection distance of atom along the - reciprocal vectors. If the distance is less than a - specified cutoff distance, relevant periodic images are generated - using box translation vectors i.e. ``l[a] + m[b] + n[c]``, where - ``[l, m, n]`` are the neighbouring cell indices relative to the central cell, - and ``[a, b, c]`` are the box vectors. For instance, an atom close to - ``XY`` plane containing origin will generate a periodic image - outside the central cell and close to the opposite `XY` plane - of the box i.e. at ``0[a] + 0[b] + 1[c]``. - Similarly, if the particle is close to more than - one box walls, images along the diagonals are also generated :: - - - | x x - +---------------+ | +---------------+ - | | | | | - | | | | | - | | | | | - | o | | x | o | - +---------------+ | +---------------+ - | - - - - Parameters - ---------- - coordinates : array - Input coordinate array to generate duplicate images - in the vicinity of the central cell. All the coordinates - must be within the primary unit cell. (dtype = numpy.float32) - box : array - Box dimension of shape (6, ). The dimensions must be - provided in the same format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: - ``[lx, ly, lz, alpha, beta, gamma]`` (dtype = numpy.float32) - r : float - thickness of cutoff region for duplicate image generation - - Returns - ------- - output : array - coordinates of duplicate(augmented) particles (dtype = numpy.float32) - indices : array - original indices of the augmented coordinates (dtype = numpy.int64) - A map which translates the indices of augmented particles - to their original particle index such that - ``indices[augmentedindex] = originalindex`` - - Note - ---- - Output doesnot return coordinates from the initial array. - To merge the particles with their respective images, following operation - needs to be superseded after generating the images: - - .. code-block:: python - - images, mapping = augment_coordinates(coordinates, box, max_cutoff) - all_coords = np.concatenate([coordinates, images]) - - - See Also - -------- - MDAnalysis.lib._augment.undo_augment - - - .. versionadded:: 0.19.0 - """ - cdef bint lo_x, hi_x, lo_y, hi_y, lo_z, hi_z - cdef int i, j, N - cdef float norm - cdef float shiftX[3] - cdef float shiftY[3] - cdef float shiftZ[3] - cdef float coord[3] - cdef float end[3] - cdef float other[3] - cdef float dm[3][3] - cdef float reciprocal[3][3] - - dm = triclinic_vectors(box) - - for i in range(3): - shiftX[i] = dm[0][i] - shiftY[i] = dm[1][i] - shiftZ[i] = dm[2][i] - end[i] = dm[0][i] + dm[1][i] + dm[2][i] - # Calculate reciprocal vectors - _cross(&dm[1][0], &dm[2][0], &reciprocal[0][0]) - _cross(&dm[2][0], &dm[0][0], &reciprocal[1][0]) - _cross(&dm[0][0], &dm[1][0], &reciprocal[2][0]) - # Normalize - for i in range(3): - norm = _norm(&reciprocal[i][0]) - for j in range(3): - reciprocal[i][j] = reciprocal[i][j]/norm - - N = coordinates.shape[0] - - cdef vector[float] output - cdef vector[int] indices - - for i in range(N): - for j in range(3): - coord[j] = coordinates[i, j] - other[j] = end[j] - coordinates[i, j] - # identify the condition - lo_x = _dot(&coord[0], &reciprocal[0][0]) <= r - hi_x = _dot(&other[0], &reciprocal[0][0]) <= r - lo_y = _dot(&coord[0], &reciprocal[1][0]) <= r - hi_y = _dot(&other[0], &reciprocal[1][0]) <= r - lo_z = _dot(&coord[0], &reciprocal[2][0]) <= r - hi_z = _dot(&other[0], &reciprocal[2][0]) <= r - - if lo_x: - # if X, face piece - for j in range(3): - # add to output - output.push_back(coord[j] + shiftX[j]) - # keep record of which index this augmented - # position was created from - indices.push_back(i) - - if lo_y: - # if X&Y, edge piece - for j in range(3): - output.push_back(coord[j] + shiftX[j] + shiftY[j]) - indices.push_back(i) - - if lo_z: - # if X&Y&Z, corner piece - for j in range(3): - output.push_back(coord[j] + shiftX[j] + shiftY[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] + shiftX[j] + shiftY[j] - shiftZ[j]) - indices.push_back(i) - - elif hi_y: - for j in range(3): - output.push_back(coord[j] + shiftX[j] - shiftY[j]) - indices.push_back(i) - - if lo_z: - for j in range(3): - output.push_back(coord[j] + shiftX[j] - shiftY[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] + shiftX[j] - shiftY[j] - shiftZ[j]) - indices.push_back(i) - - if lo_z: - for j in range(3): - output.push_back(coord[j] + shiftX[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] + shiftX[j] - shiftZ[j]) - indices.push_back(i) - - elif hi_x: - for j in range(3): - output.push_back(coord[j] - shiftX[j]) - indices.push_back(i) - - if lo_y: - for j in range(3): - output.push_back(coord[j] - shiftX[j] + shiftY[j]) - indices.push_back(i) - - if lo_z: - for j in range(3): - output.push_back(coord[j] - shiftX[j] + shiftY[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] - shiftX[j] + shiftY[j] - shiftZ[j]) - indices.push_back(i) - - elif hi_y: - for j in range(3): - output.push_back(coord[j] - shiftX[j] - shiftY[j]) - indices.push_back(i) - - if lo_z: - for j in range(3): - output.push_back(coord[j] - shiftX[j] - shiftY[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] - shiftX[j] - shiftY[j] - shiftZ[j]) - indices.push_back(i) - - if lo_z: - for j in range(3): - output.push_back(coord[j] - shiftX[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] - shiftX[j] - shiftZ[j]) - indices.push_back(i) - - if lo_y: - for j in range(3): - output.push_back(coord[j] + shiftY[j]) - indices.push_back(i) - - if lo_z: - for j in range(3): - output.push_back(coord[j] + shiftY[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] + shiftY[j] - shiftZ[j]) - indices.push_back(i) - - elif hi_y: - for j in range(3): - output.push_back(coord[j] - shiftY[j]) - indices.push_back(i) - - if lo_z: - for j in range(3): - output.push_back(coord[j] - shiftY[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] - shiftY[j] - shiftZ[j]) - indices.push_back(i) - - if lo_z: - for j in range(3): - output.push_back(coord[j] + shiftZ[j]) - indices.push_back(i) - - elif hi_z: - for j in range(3): - output.push_back(coord[j] - shiftZ[j]) - indices.push_back(i) - n = indices.size() - return np.asarray(output, dtype=np.float32).reshape(n, 3), np.asarray(indices, dtype=np.int64) - - -@cython.boundscheck(False) -@cython.wraparound(False) -def undo_augment(np.int64_t[:] results, np.int64_t[:] translation, int nreal): - """Translate augmented indices back to original indices - - Parameters - ---------- - results : numpy.ndarray - indices of coordinates, including "augmented" indices (dtype = numpy.int64) - translation : numpy.ndarray - Map to link the augmented indices to the original particle indices - such that ``translation[augmentedindex] = originalindex`` - (dtype = numpy.int64) - nreal : int - number of real coordinates, i.e. values in results equal or larger - than this need to be translated to their real counterpart - - - Returns - ------- - results : numpy.ndarray - modified input results with all the augmented indices - translated to their corresponding initial original indices - (dtype = numpy.int64) - - Note - ---- - Modifies the results array in place - - See Also - -------- - 'MDAnalysis.lib._augment.augment_coordinates' - - - .. versionadded:: 0.19.0 - """ - cdef int N - cdef ssize_t i - N = results.shape[0] - - for i in range(N): - if results[i] >= nreal: - results[i] = translation[results[i] - nreal] - return np.asarray(results, dtype=np.int64) +# -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; -*- +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 +# +# MDAnalysis --- https://www.mdanalysis.org +# Copyright (c) 2006-2017 The MDAnalysis Development Team and contributors +# (see the file AUTHORS for the full list of names) +# +# Released under the GNU Public Licence, v2 or any higher version +# +# Please cite your use of MDAnalysis in published work: +# +# R. J. Gowers, M. Linke, J. Barnoud, T. J. E. Reddy, M. N. Melo, S. L. Seyler, +# D. L. Dotson, J. Domanski, S. Buchoux, I. M. Kenney, and O. Beckstein. +# MDAnalysis: A Python package for the rapid analysis of molecular dynamics +# simulations. In S. Benthall and S. Rostrup editors, Proceedings of the 15th +# Python in Science Conference, pages 102-109, Austin, TX, 2016. SciPy. +# +# N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and O. Beckstein. +# MDAnalysis: A Toolkit for the Analysis of Molecular Dynamics Simulations. +# J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787 +# +# + +import cython +import numpy as np +from .mdamath import triclinic_vectors +cimport numpy as np +cimport _cutil +from _cutil cimport _dot ,_norm, _cross + +from libcpp.vector cimport vector + + +__all__ = ['augment_coordinates', 'undo_augment'] + + +@cython.boundscheck(False) +@cython.wraparound(False) +def augment_coordinates(float[:, ::1] coordinates, float[:] box, float r): + r"""Calculates the relevant images of particles which are within a + distance 'r' from the box walls + + The algorithm works by generating explicit periodic images of + interior atoms residing close to any of the six box walls. + The steps involved in generating images involves + evaluation of reciprocal vectors for the given box vectors + followed by calculation of projection distance of atom along the + reciprocal vectors. If the distance is less than a + specified cutoff distance, relevant periodic images are generated + using box translation vectors i.e. ``l[a] + m[b] + n[c]``, where + ``[l, m, n]`` are the neighbouring cell indices relative to the central cell, + and ``[a, b, c]`` are the box vectors. For instance, an atom close to + ``XY`` plane containing origin will generate a periodic image + outside the central cell and close to the opposite `XY` plane + of the box i.e. at ``0[a] + 0[b] + 1[c]``. + Similarly, if the particle is close to more than + one box walls, images along the diagonals are also generated :: + + + | x x + +---------------+ | +---------------+ + | | | | | + | | | | | + | | | | | + | o | | x | o | + +---------------+ | +---------------+ + | + + + + Parameters + ---------- + coordinates : numpy.ndarray + Input coordinate array of dtype ``numpy.float32`` used to generate + duplicate images in the vicinity of the central cell. All coordinates + must be within the primary unit cell. + box : numpy.ndarray + Box dimensions of shape ``(6,)`` and dtype ``numpy.float32``. The + dimensions must be provided in the same format as returned + by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: + ``[lx, ly, lz, alpha, beta, gamma]`` + r : float + Thickness of cutoff region for duplicate image generation. + + Returns + ------- + output : numpy.ndarray + Coordinates of duplicate (augmented) particles (dtype ``numpy.float32``). + indices : numpy.ndarray + Original indices of the augmented coordinates (dtype ``numpy.int64``). + Maps the indices of augmented particles to their original particle index + such that ``indices[augmented_index] = original_index``. + + Note + ---- + Output does not return coordinates from the initial array. + To merge the particles with their respective images, the following operation + is necessary when generating the images: + + .. code-block:: python + + images, mapping = augment_coordinates(coordinates, box, max_cutoff) + all_coords = np.concatenate([coordinates, images]) + + + See Also + -------- + :meth:`undo_augment` + + + .. versionadded:: 0.19.0 + """ + cdef bint lo_x, hi_x, lo_y, hi_y, lo_z, hi_z + cdef int i, j, N + cdef float norm + cdef float shiftX[3] + cdef float shiftY[3] + cdef float shiftZ[3] + cdef float coord[3] + cdef float end[3] + cdef float other[3] + cdef float dm[3][3] + cdef float reciprocal[3][3] + + dm = triclinic_vectors(box) + + for i in range(3): + shiftX[i] = dm[0][i] + shiftY[i] = dm[1][i] + shiftZ[i] = dm[2][i] + end[i] = dm[0][i] + dm[1][i] + dm[2][i] + # Calculate reciprocal vectors + _cross(&dm[1][0], &dm[2][0], &reciprocal[0][0]) + _cross(&dm[2][0], &dm[0][0], &reciprocal[1][0]) + _cross(&dm[0][0], &dm[1][0], &reciprocal[2][0]) + # Normalize + for i in range(3): + norm = _norm(&reciprocal[i][0]) + for j in range(3): + reciprocal[i][j] = reciprocal[i][j]/norm + + N = coordinates.shape[0] + + cdef vector[float] output + cdef vector[int] indices + + for i in range(N): + for j in range(3): + coord[j] = coordinates[i, j] + other[j] = end[j] - coordinates[i, j] + # identify the condition + lo_x = _dot(&coord[0], &reciprocal[0][0]) <= r + hi_x = _dot(&other[0], &reciprocal[0][0]) <= r + lo_y = _dot(&coord[0], &reciprocal[1][0]) <= r + hi_y = _dot(&other[0], &reciprocal[1][0]) <= r + lo_z = _dot(&coord[0], &reciprocal[2][0]) <= r + hi_z = _dot(&other[0], &reciprocal[2][0]) <= r + + if lo_x: + # if X, face piece + for j in range(3): + # add to output + output.push_back(coord[j] + shiftX[j]) + # keep record of which index this augmented + # position was created from + indices.push_back(i) + + if lo_y: + # if X&Y, edge piece + for j in range(3): + output.push_back(coord[j] + shiftX[j] + shiftY[j]) + indices.push_back(i) + + if lo_z: + # if X&Y&Z, corner piece + for j in range(3): + output.push_back(coord[j] + shiftX[j] + shiftY[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] + shiftX[j] + shiftY[j] - shiftZ[j]) + indices.push_back(i) + + elif hi_y: + for j in range(3): + output.push_back(coord[j] + shiftX[j] - shiftY[j]) + indices.push_back(i) + + if lo_z: + for j in range(3): + output.push_back(coord[j] + shiftX[j] - shiftY[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] + shiftX[j] - shiftY[j] - shiftZ[j]) + indices.push_back(i) + + if lo_z: + for j in range(3): + output.push_back(coord[j] + shiftX[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] + shiftX[j] - shiftZ[j]) + indices.push_back(i) + + elif hi_x: + for j in range(3): + output.push_back(coord[j] - shiftX[j]) + indices.push_back(i) + + if lo_y: + for j in range(3): + output.push_back(coord[j] - shiftX[j] + shiftY[j]) + indices.push_back(i) + + if lo_z: + for j in range(3): + output.push_back(coord[j] - shiftX[j] + shiftY[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] - shiftX[j] + shiftY[j] - shiftZ[j]) + indices.push_back(i) + + elif hi_y: + for j in range(3): + output.push_back(coord[j] - shiftX[j] - shiftY[j]) + indices.push_back(i) + + if lo_z: + for j in range(3): + output.push_back(coord[j] - shiftX[j] - shiftY[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] - shiftX[j] - shiftY[j] - shiftZ[j]) + indices.push_back(i) + + if lo_z: + for j in range(3): + output.push_back(coord[j] - shiftX[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] - shiftX[j] - shiftZ[j]) + indices.push_back(i) + + if lo_y: + for j in range(3): + output.push_back(coord[j] + shiftY[j]) + indices.push_back(i) + + if lo_z: + for j in range(3): + output.push_back(coord[j] + shiftY[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] + shiftY[j] - shiftZ[j]) + indices.push_back(i) + + elif hi_y: + for j in range(3): + output.push_back(coord[j] - shiftY[j]) + indices.push_back(i) + + if lo_z: + for j in range(3): + output.push_back(coord[j] - shiftY[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] - shiftY[j] - shiftZ[j]) + indices.push_back(i) + + if lo_z: + for j in range(3): + output.push_back(coord[j] + shiftZ[j]) + indices.push_back(i) + + elif hi_z: + for j in range(3): + output.push_back(coord[j] - shiftZ[j]) + indices.push_back(i) + n = indices.size() + return np.asarray(output, dtype=np.float32).reshape(n, 3), np.asarray(indices, dtype=np.int64) + + +@cython.boundscheck(False) +@cython.wraparound(False) +def undo_augment(np.int64_t[:] results, np.int64_t[:] translation, int nreal): + """Translate augmented indices back to original indices + + Parameters + ---------- + results : numpy.ndarray + Array of coordinate indices (dtype ``numpy.int64``), including "augmented" + indices. + translation : numpy.ndarray + Map to link the augmented indices to the original particle indices + such that ``translation[augmentedindex] = originalindex`` + (dtype = numpy.int64) + nreal : int + number of real coordinates, i.e. values in results equal or larger + than this need to be translated to their real counterpart + + + Returns + ------- + results : numpy.ndarray + Modified input `results` with all the augmented indices translated to + their corresponding initial original indices (dtype ``numpy.int64``) + + Note + ---- + Modifies the results array in place. + + See Also + -------- + :meth:`augment_coordinates` + + + .. versionadded:: 0.19.0 + """ + cdef int N + cdef ssize_t i + N = results.shape[0] + + for i in range(N): + if results[i] >= nreal: + results[i] = translation[results[i] - nreal] + return np.asarray(results, dtype=np.int64) From 59860e70b765e75bd62e0ea653e3ca0988c06546 Mon Sep 17 00:00:00 2001 From: zeman Date: Mon, 3 Sep 2018 15:36:02 +0200 Subject: [PATCH 04/10] improved docstrings in lib/_augment.pyx --- package/MDAnalysis/lib/_augment.pyx | 82 ++++++++++++++--------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/package/MDAnalysis/lib/_augment.pyx b/package/MDAnalysis/lib/_augment.pyx index 9e8fe263c76..3dd6bca90a9 100644 --- a/package/MDAnalysis/lib/_augment.pyx +++ b/package/MDAnalysis/lib/_augment.pyx @@ -37,43 +37,44 @@ __all__ = ['augment_coordinates', 'undo_augment'] @cython.boundscheck(False) @cython.wraparound(False) def augment_coordinates(float[:, ::1] coordinates, float[:] box, float r): - r"""Calculates the relevant images of particles which are within a - distance 'r' from the box walls - - The algorithm works by generating explicit periodic images of - interior atoms residing close to any of the six box walls. - The steps involved in generating images involves - evaluation of reciprocal vectors for the given box vectors - followed by calculation of projection distance of atom along the - reciprocal vectors. If the distance is less than a - specified cutoff distance, relevant periodic images are generated - using box translation vectors i.e. ``l[a] + m[b] + n[c]``, where - ``[l, m, n]`` are the neighbouring cell indices relative to the central cell, - and ``[a, b, c]`` are the box vectors. For instance, an atom close to - ``XY`` plane containing origin will generate a periodic image - outside the central cell and close to the opposite `XY` plane - of the box i.e. at ``0[a] + 0[b] + 1[c]``. - Similarly, if the particle is close to more than - one box walls, images along the diagonals are also generated :: - - - | x x - +---------------+ | +---------------+ - | | | | | - | | | | | - | | | | | - | o | | x | o | - +---------------+ | +---------------+ - | - - + r"""Calculates the periodic images of particles which are within a distance + `r` from the box walls. + + The algorithm works by generating explicit periodic images of atoms residing + close to any of the six box walls. The steps involved in generating images + involves the evaluation of reciprocal box vectors followed by the + calculation of distances of atoms from the walls by means of projection onto + the reciprocal vectors. If the distance is less than a specified cutoff + distance, relevant periodic images are generated using box translation + vectors :math:`\vec{t}` with + + .. math:: \vec{t}=l\cdot\vec{a}+m\cdot\vec{b}+n\cdot \vec{c}\,, + + where :math:`l,\,m,\,n \in \{-1,\,0,\,1\}` are the neighboring cell indices + in :math:`x`-, :math:`y`-, and :math:`z`-direction relative to the central + cell with box vectors :math:`\vec{a},\,\vec{b},\,\vec{c}`. + + For instance, an atom close to the :math:`xy`-plane containing the origin + will generate a periodic image outside the central cell and close to the + opposite :math:`xy`-plane of the box, i.e., shifted by + :math:`\vec{t} = 0\cdot\vec{a}+0\cdot\vec{b}+1\cdot\vec{c}=\vec{c}`. + + Likewise, if the particle is close to more than one box walls, images along + the diagonals are also generated:: + + x x + +------------+ +------------+ + | | augment | | + | | -------> | | + | o | x | o | + +------------+ +------------+ Parameters ---------- coordinates : numpy.ndarray - Input coordinate array of dtype ``numpy.float32`` used to generate - duplicate images in the vicinity of the central cell. All coordinates - must be within the primary unit cell. + Input coordinate array of shape ``(n, 3)`` and dtype ``numpy.float32`` + used to generate duplicate images in the vicinity of the central cell. All + coordinates must be within the primary unit cell. box : numpy.ndarray Box dimensions of shape ``(6,)`` and dtype ``numpy.float32``. The dimensions must be provided in the same format as returned @@ -100,7 +101,7 @@ def augment_coordinates(float[:, ::1] coordinates, float[:] box, float r): .. code-block:: python images, mapping = augment_coordinates(coordinates, box, max_cutoff) - all_coords = np.concatenate([coordinates, images]) + all_coords = numpy.concatenate([coordinates, images]) See Also @@ -303,17 +304,16 @@ def undo_augment(np.int64_t[:] results, np.int64_t[:] translation, int nreal): Parameters ---------- results : numpy.ndarray - Array of coordinate indices (dtype ``numpy.int64``), including "augmented" - indices. + Array of coordinate indices with dtype ``numpy.int64``, including + "augmented" indices. translation : numpy.ndarray - Map to link the augmented indices to the original particle indices - such that ``translation[augmentedindex] = originalindex`` - (dtype = numpy.int64) + Index map (dtype ``numpy.int64``) linking the augmented indices to the + original particle indices such that + ``translation[augmented_index] = real_index`` nreal : int - number of real coordinates, i.e. values in results equal or larger + Number of real coordinates, i.e., values in results equal or larger than this need to be translated to their real counterpart - Returns ------- results : numpy.ndarray From 280efad6da31dd463c4b1c852f2b963b950bd662 Mon Sep 17 00:00:00 2001 From: zeman Date: Mon, 3 Sep 2018 16:25:41 +0200 Subject: [PATCH 05/10] improved docstrings in lib/_augment.pyx --- package/MDAnalysis/lib/_augment.pyx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package/MDAnalysis/lib/_augment.pyx b/package/MDAnalysis/lib/_augment.pyx index 3dd6bca90a9..b9dd8cfba9f 100644 --- a/package/MDAnalysis/lib/_augment.pyx +++ b/package/MDAnalysis/lib/_augment.pyx @@ -299,26 +299,26 @@ def augment_coordinates(float[:, ::1] coordinates, float[:] box, float r): @cython.boundscheck(False) @cython.wraparound(False) def undo_augment(np.int64_t[:] results, np.int64_t[:] translation, int nreal): - """Translate augmented indices back to original indices + """Translate augmented indices back to original indices. Parameters ---------- results : numpy.ndarray - Array of coordinate indices with dtype ``numpy.int64``, including + Array of dtype ``numpy.int64`` containing coordinate indices, including "augmented" indices. translation : numpy.ndarray - Index map (dtype ``numpy.int64``) linking the augmented indices to the + Index map of dtype ``numpy.int64`` linking the augmented indices to the original particle indices such that - ``translation[augmented_index] = real_index`` + ``translation[augmented_index] = original_index``. nreal : int - Number of real coordinates, i.e., values in results equal or larger - than this need to be translated to their real counterpart + Number of real coordinates, i.e., indices in `results` equal or larger + than this need to be mapped to their real counterpart. Returns ------- results : numpy.ndarray Modified input `results` with all the augmented indices translated to - their corresponding initial original indices (dtype ``numpy.int64``) + their corresponding initial original indices. Note ---- From bf18cdad0480982a16c5c92e618765409ba7edf0 Mon Sep 17 00:00:00 2001 From: zeman Date: Tue, 11 Sep 2018 18:47:57 +0200 Subject: [PATCH 06/10] improved all docstrings in lib/distances.py --- package/MDAnalysis/lib/distances.py | 1128 ++++++++++++++++----------- 1 file changed, 692 insertions(+), 436 deletions(-) diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index 3709d390e16..2e646d9bf14 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -24,18 +24,18 @@ """Fast distance array computation --- :mod:`MDAnalysis.lib.distances` =================================================================== -Fast C-routines to calculate distance arrays from coordinate -arrays. Many of the functions also exist in parallel versions, that -typically provide higher performance than the serial code. -The boolean attribute MDAnalysis.lib.distances.USED_OPENMP can be -checked to see if OpenMP was used in the compilation of MDAnalysis. +Fast C-routines to calculate arrays of distances or angles from coordinate +arrays. Many of the functions also exist in parallel versions, which typically +provide higher performance than the serial code. +The boolean attribute `MDAnalysis.lib.distances.USED_OPENMP` can be checked to +see if OpenMP was used in the compilation of MDAnalysis. Selection of acceleration ("backend") ------------------------------------- -All functions take the optional keyword *backend*, which determines -the type of acceleration. Currently, the following choices are -implemented (*backend* is case-insensitive): +All functions take the optional keyword `backend`, which determines the type of +acceleration. Currently, the following choices are implemented (`backend` is +case-insensitive): .. Table:: Available *backends* for accelerated distance functions. @@ -52,20 +52,8 @@ Functions --------- - -.. autofunction:: distance_array(reference, configuration [, box [, result [, backend]]]) -.. autofunction:: self_distance_array(reference [, box [,result [, backend]]]) -.. autofunction:: calc_bonds(atom1, atom2 [, box, [, result [, backend]]]) -.. autofunction:: calc_angles(atom1, atom2, atom3 [,box [, result [, backend]]]) -.. autofunction:: calc_dihedrals(atom1, atom2, atom3, atom4 [,box [, result [, backend]]]) -.. autofunction:: apply_PBC(coordinates, box [, backend]) -.. autofunction:: capped_distance(reference, configuration, max_cutoff [, min_cutoff [, box [, method]]]) -.. autofunction:: self_capped_distance(reference, max_cutoff, [, min_cutoff [, box [, method]]]) -.. autofunction:: transform_RtoS(coordinates, box [, backend]) -.. autofunction:: transform_StoR(coordinates, box [,backend]) -.. autofunction:: MDAnalysis.lib._augment.augment_coordinates(coordinates, box, radius) -.. autofunction:: MDAnalysis.lib._augment.undo_augment(indices, translation, nreal) - +.. autofunction:: augment_coordinates(coordinates, box, r) +.. autofunction:: undo_augment(results, translation, nreal) """ from __future__ import division, absolute_import from six.moves import range @@ -94,15 +82,15 @@ del importlib def _run(funcname, args=None, kwargs=None, backend="serial"): - """Helper function to select a backend function *funcname*.""" + """Helper function to select a backend function `funcname`.""" args = args if args is not None else tuple() kwargs = kwargs if kwargs is not None else dict() backend = backend.lower() try: func = getattr(_distances[backend], funcname) except KeyError: - raise ValueError("Function {0} not available with backend {1}; try one of: {2}".format( - funcname, backend, ", ".join(_distances.keys()))) + raise ValueError("Function {0} not available with backend {1}; try one " + "of: {2}".format(funcname, backend, _distances.keys())) return func(*args, **kwargs) # serial versions are always available (and are typically used within @@ -162,7 +150,7 @@ def _check_box(box): If `box` is not of the form ``[lx, ly, lz, alpha, beta, gamma]`` or contains data that is not convertible to ``numpy.float32``. - .. seealso: :meth:`~MDAnalysis.lib.mdamath.triclinic_vectors` + .. seealso: :meth:`MDAnalysis.lib.mdamath.triclinic_vectors` .. versionchanged: 0.19.0 * Enforced correspondence of `box` with specified format. * Added automatic conversion of input to :class:`numpy.ndarray` with @@ -220,55 +208,59 @@ def _check_result_array(result, shape): # raise ValueError("{0} is not C-contiguous.".format(desc)) return result + @check_coords('reference', 'configuration', enforce_copy=False, reduce_result_if_single=False, check_lengths_match=False) def distance_array(reference, configuration, box=None, result=None, backend="serial"): - """Calculate all distances between a reference set and another configuration. + """Calculate all possible distances between a reference set and another + configuration. - If there are *i* positions in reference, and *j* positions in configuration, - will calculate a *i* x *j* array of distances - If an *box* is supplied then a minimum image convention is used when - calculating distances. + If there are ``n`` positions in `reference` and ``m`` positions in + `configuration`, a distance array of shape ``(n, m)`` will be computed. - If a 2D numpy array of dtype ``numpy.float64`` with the shape ``(len(reference), - len(configuration))`` is provided in *result* then this preallocated array is - filled. This can speed up calculations. + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. + + If a 2D numpy array of dtype ``numpy.float64`` with the shape ``(n, m)`` + is provided in `result`, then this preallocated array is filled. This can + speed up calculations. Parameters ---------- reference : numpy.ndarray - Reference coordinate array of shape ``(n, 3)`` (``dtype`` is arbitrary, - will be converted to ``dtype=numpy.float32`` internally) + Reference coordinate array of shape ``(3,)`` or ``(n, 3)`` (dtype is + arbitrary, will be converted to ``numpy.float32`` internally). configuration : numpy.ndarray - Configuration coordinate array of shape ``(m, 3)`` (``dtype`` is - arbitrary, will be converted to ``dtype=numpy.float32`` internally) - box : numpy.ndarray or None - Dimensions of the cell; if provided, the minimum image convention is - applied. The dimensions must be provided in the same format as returned - by by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: ``[lx, - ly, lz, alpha, beta, gamma]``. - result : numpy.ndarray(dtype=numpy.float64), optional - Preallocated result array which must have the - shape ``(len(ref), len(conf))`` and ``dtype=numpy.float64``. + Configuration coordinate array of shape ``(3,)`` or ``(m, 3)`` (dtype is + arbitrary, will be converted to ``numpy.float32`` internally). + box : array_like, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + result : numpy.ndarray, optional + Preallocated result array which must have the shape ``(n, m)`` and dtype + ``numpy.float64``. Avoids creating the array which saves time when the function - is called repeatedly. [``None``] - backend : str - Select the type of acceleration; "serial" is always available. Other - possibilities are "OpenMP" (OpenMP). + is called repeatedly. + backend : str, optional + Select the type of acceleration; ``'serial'`` is always available. + Another possibility is ``'OpenMP'``. Returns ------- d : numpy.ndarray - ``(len(reference),len(configuration))`` numpy array with the distances - ``d[i,j]`` between reference coordinates `i` and configuration - coordinates `j`. + Array with shape ``(n, m)`` containing the distances ``d[i,j]`` between + reference coordinates ``i`` and configuration coordinates ``j``. .. versionchanged:: 0.13.0 Added *backend* keyword. .. versionchanged:: 0.19.0 Internal dtype conversion of input coordinates to ``numpy.float32``. + Now also accepts single coordinates as input. """ confnum = configuration.shape[0] refnum = reference.shape[0] @@ -292,47 +284,50 @@ def distance_array(reference, configuration, box=None, result=None, return distances + @check_coords('reference', enforce_copy=False, reduce_result_if_single=False) def self_distance_array(reference, box=None, result=None, backend="serial"): - """Calculate all distances within a configuration *reference*. + """Calculate all possible distances within a configuration `reference`. - If a *box* is supplied then a minimum image convention is used before - calculating distances. + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. If a 1D numpy array of dtype ``numpy.float64`` with the shape - ``(N*(N-1)/2)`` is provided in *result* then this preallocated array - is filled. This can speed up calculations. + ``(n*(n-1)/2,)`` is provided in `result`, then this preallocated array is + filled. This can speed up calculations. Parameters ---------- reference : numpy.ndarray - Reference coordinate array with ``N=len(ref)`` coordinates (``dtype`` is - arbitrary, will be converted to ``dtype=numpy.float32`` internally) - box : numpy.ndarray or None - Dimensions of the cell; if provided, the minimum image convention is - applied. The dimensions must be provided in the same format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: ``[lx, - ly, lz, alpha, beta, gamma]``. - result : numpy.ndarray(dtype=numpy.float64), optional - Preallocated result array which must have the shape ``(N*(N-1)/2,)`` and + Reference coordinate array of shape ``(3,)`` or ``(n, 3)`` (dtype is + arbitrary, will be converted to ``numpy.float32`` internally). + box : array_like, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + result : numpy.ndarray, optional + Preallocated result array which must have the shape ``(n*(n-1)/2,)`` and dtype ``numpy.float64``. Avoids creating the array which saves time when - the function is called repeatedly. [``None``] - backend : str - Select the type of acceleration; "serial" is always available. Other - possibilities are "OpenMP" (OpenMP). + the function is called repeatedly. + backend : str, optional + Select the type of acceleration; ``'serial'`` is always available. + Another possibility is ``'OpenMP'``. Returns ------- d : numpy.ndarray - ``N*(N-1)/2`` numpy 1D array with the distances dist[i,j] between ref - coordinates i and j at position d[k]. Loop through d: + Array with shape ``(n*(n-1)/2,)`` containing the distances ``dist[i,j]`` + between reference coordinates ``i`` and ``j`` at position ``d[k]``. Loop + through ``d``: .. code-block:: python - for i in range(N): - for j in range(i+1, N): + for i in range(n): + for j in range(i + 1, n): k += 1 - dist[i,j] = d[k] + dist[i, j] = d[k] .. versionchanged:: 0.13.0 @@ -367,75 +362,82 @@ def self_distance_array(reference, box=None, result=None, backend="serial"): def capped_distance(reference, configuration, max_cutoff, min_cutoff=None, box=None, method=None, return_distances=True): - """Calculates the pairs and distances within a specified distance + """Calculates pairs of indices corresponding to entries in the `reference` + and `configuration` arrays which are separated by a distance lying within + the specified cutoff(s). Optionally, these distances can be returned as + well. - If a *box* is supplied, then a minimum image convention is used - to evaluate the distances. + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. - An automatic guessing of optimized method to calculate the distances is + An automatic guessing of the optimal method to calculate the distances is included in the function. An optional keyword for the method is also - provided. Users can override the method with this functionality. - Currently pkdtree and bruteforce are implemented. - + provided. Users can enforce a particular method with this functionality. + Currently brute force, grid search, and periodic KDtree methods are + implemented. Parameters ----------- - reference : array - reference coordinates array with shape ``reference.shape = (3,)`` - or ``reference.shape = (len(reference), 3)`` - configuration : array - Configuration coordinate array with shape ``reference.shape = (3,)`` - or ``reference.shape = (len(reference), 3)`` + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)``. + configuration : numpy.ndarray + Configuration coordinate array with shape ``(3,)`` or ``(m, 3)``. max_cutoff : float - Maximum cutoff distance between the reference and configuration - min_cutoff : (optional) float - Minimum cutoff distance between reference and configuration [None] - box : (optional) array or None - The dimensions, if provided, must be provided in the same - The unitcell dimesions for this system format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: - ``[lx,ly, lz, alpha, beta, gamma]``. Minimum image convention - is applied if the box is provided [None] - method : (optional) 'bruteforce' or 'pkdtree' or 'None' - Keyword to override the automatic guessing of method built-in - in the function [None] - return_distances : (optional) 'True'/'False' - Function returns distances if set to 'True' + Maximum cutoff distance between the reference and configuration. + min_cutoff : float, optional + Minimum cutoff distance between reference and configuration. + box : array_like, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + method : str, optional + Keyword to override the automatic guessing ofthe employed search method. + Can be ``'bruteforce'``, ``'nsgrid'``, or ``'pkdtree'``. + return_distances : bool, optional + If set to ``True``, distances will also be returned. Returns ------- - pairs : array - Pair of indices, one from each reference and configuration such that - distance between them is within the ``max_cutoff`` and ``min_cutoff`` - pairs[i,j] contains the indices i from reference coordinates, and - j from configuration - distances : (optional) array - Distances corresponding to each pair of indices. - d[k] corresponding to the pairs[i,j] gives the distance between - i-th and j-th coordinate in reference and configuration respectively - Returns only if ``return_distances`` is set to `True` + pairs : numpy.ndarray + Pairs of indices, corresponding to coordinates in the `reference` and + `configuration` arrays such that the distance between them lies within + the interval (`min_cutoff`, `max_cutoff`]. + Each row in `pairs` is an index pair ``[i, j]`` corresponding to the + ``i``-th coordinate in `reference` and the ``j``-th coordinate in + `configuration`. + distances : numpy.ndarray, optional + Distances corresponding to each pair of indices. Only returned if + `return_distances` is ``True``. ``distances[k]`` corresponds to the + ``k``-th pair returned in `pairs` and gives the distance between the + coordinates ``reference[pairs[k, 0]]`` and + ``configuration[pairs[k, 1]]``. .. code-block:: python - pairs, distances = capped_distances(reference, coordinates, max_cutoff) - for indx, [a,b] in enumerate(pairs): - coord1 = reference[a] - coord2 = configuration[b] - distance = distances[indx] + pairs, distances = capped_distances(reference, configuration, + max_cutoff, return_distances=True) + for k, [i, j] in enumerate(pairs): + coord1 = reference[i] + coord2 = configuration[j] + distance = distances[k] Note ----- - Currently only supports brute force and Periodic KDtree + Currently supports brute force, grid-based, and periodic KDtree search + methods. - .. SeeAlso:: :func:'MDAnalysis.lib.distances.distance_array' - .. SeeAlso:: :func:'MDAnalysis.lib.pkdtree.PeriodicKDTree.search' - .. SeeAlso:: :class:'MDAnalysis.lib.nsgrid.FastNS.search' + .. seealso:: :meth:`~MDAnalysis.lib.distances.distance_array` + .. seealso:: :meth:`MDAnalysis.lib.pkdtree.PeriodicKDTree.search` + .. seealso:: :meth:`MDAnalysis.lib.nsgrid.FastNS.search` """ if box is not None: + box = np.asarray(box, dtype=np.float32) if box.shape[0] != 6: - raise ValueError('Box Argument is of incompatible type. The dimension' - 'should be either None or ' - 'of the type [lx, ly, lz, alpha, beta, gamma]') + raise ValueError("Box Argument is of incompatible type. The " + "dimension should be either None or of the form " + "[lx, ly, lz, alpha, beta, gamma]") method = _determine_method(reference, configuration, max_cutoff, min_cutoff=min_cutoff, box=box, method=method) @@ -455,65 +457,61 @@ def capped_distance(reference, configuration, max_cutoff, min_cutoff=None, def _determine_method(reference, configuration, max_cutoff, min_cutoff=None, box=None, method=None): - """ - Switch between different methods based on the the optimized time. - All the rules to select the method based on the input can be - incorporated here. + """Guesses the fastest method for capped distance calculations based on the + size of the coordinate sets and the relative size of the target volume. Parameters ---------- - reference : array - reference coordinates array with shape ``reference.shape = (3,)`` - or ``reference.shape = (len(reference), 3)`` - configuration : array - Configuration coordinate array with shape ``reference.shape = (3,)`` - or ``reference.shape = (len(reference), 3)`` + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)``. + configuration : numpy.ndarray + Configuration coordinate array with shape ``(3,)`` or ``(m, 3)``. max_cutoff : float - Maximum cutoff distance between the reference and configuration - min_cutoff : (optional) float - Minimum cutoff distance between reference and configuration [None] - box : (optional) array or None - The dimensions, if provided, must be provided in the same - The unitcell dimesions for this system format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: - ``[lx,ly, lz, alpha, beta, gamma]``. Minimum image convention - is applied if the box is provided [None] - method : (optional) 'bruteforce' or 'pkdtree' or 'None' - Keyword to override the automatic guessing of method built-in - in the function [None] + Maximum cutoff distance between `reference` and `configuration` + coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` and `configuration` + coordinates. + box : numpy.ndarray + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + method : str, optional + Keyword to override the automatic guessing ofthe employed search method. + Can be ``'bruteforce'``, ``'nsgrid'``, or ``'pkdtree'``. Returns ------- - Method : Function object - Returns function object based on the rules and specified method + function : callable + The function implementing the guessed (or deliberatly chosen) method. Note ---- Currently implemented methods are present in the ``methods`` dictionary bruteforce : returns ``_bruteforce_capped`` - PKDtree : return ``_pkdtree_capped` - NSGrid : return ``_nsgrid_capped` - + PKDtree : return ``_pkdtree_capped`` + NSGrid : return ``_nsgrid_capped`` """ methods = {'bruteforce': _bruteforce_capped, 'pkdtree': _pkdtree_capped, 'nsgrid': _nsgrid_capped} if method is not None: - return methods[method] + return methods[method.lower()] if len(reference) < 10 or len(configuration) < 10: return methods['bruteforce'] - elif len(reference)*len(configuration) >= 1e8: + elif len(reference) * len(configuration) >= 1e8: # CAUTION : for large datasets, shouldnt go into 'bruteforce' # in any case. Arbitrary number, but can be characterized return methods['nsgrid'] else: if box is None: min_dim = np.array([reference.min(axis=0), - configuration.min(axis=0)]) + configuration.min(axis=0)]) max_dim = np.array([reference.max(axis=0), - configuration.max(axis=0)]) + configuration.max(axis=0)]) size = max_dim.max(axis=0) - min_dim.min(axis=0) elif np.allclose(box[3:], 90): size = box[:3] @@ -525,64 +523,134 @@ def _determine_method(reference, configuration, max_cutoff, min_cutoff=None, else: return methods['nsgrid'] + @check_coords('reference', 'configuration', enforce_copy=False, reduce_result_if_single=False, check_lengths_match=False) def _bruteforce_capped(reference, configuration, max_cutoff, min_cutoff=None, box=None, return_distances=True): - """Internal method for bruteforce calculations + """Capped distance evaluations using a brute force method. + + Computes and returns an array containing pairs of indices corresponding to + entries in the `reference` and `configuration` arrays which are separated by + a distance lying within the specified cutoff(s). Employs naive distance + computations (brute force) to find relevant distances. + + Optionally, these distances can be returned as well. + + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. - Uses naive distance calulations and returns a list - containing the indices with one from each - reference and configuration arrays, such that the distance between - them is less than the specified cutoff distance + Parameters + ---------- + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)`` (dtype will + be converted to ``numpy.float32`` internally). + configuration : array + Configuration coordinate array with shape ``(3,)`` or ``(m, 3)`` (dtype + will be converted to ``numpy.float32`` internally). + max_cutoff : float + Maximum cutoff distance between `reference` and `configuration` + coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` and `configuration` + coordinates. + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + return_distances : bool, optional + If set to ``True``, distances will also be returned. Returns ------- - pairs : array - Every ``[i, j]`` pair is such that atom-index ``i`` is - from reference and ``j`` from configuration array - distance: (optional) array - Distance between ``reference[i]`` and ``configuration[j]`` - atom coordinate. Only returns when ``return_distances`` - is set to ``True`` - + pairs : numpy.ndarray + Pairs of indices, corresponding to coordinates in the `reference` and + `configuration` arrays such that the distance between them lies within + the interval (`min_cutoff`, `max_cutoff`]. + Each row in `pairs` is an index pair ``[i, j]`` corresponding to the + ``i``-th coordinate in `reference` and the ``j``-th coordinate in + `configuration`. + distances : numpy.ndarray, optional + Distances corresponding to each pair of indices. Only returned if + `return_distances` is ``True``. ``distances[k]`` corresponds to the + ``k``-th pair returned in `pairs` and gives the distance between the + coordinates ``reference[pairs[k, 0]]`` and + ``configuration[pairs[k, 1]]``. """ - pairs = [] - - distance = distance_array(reference, configuration, box=box) + distances = distance_array(reference, configuration, box=box) if min_cutoff is not None: - mask = np.where((distance <= max_cutoff) & (distance > min_cutoff)) + mask = np.where((distances <= max_cutoff) & (distances > min_cutoff)) else: - mask = np.where((distance <= max_cutoff)) + mask = np.where((distances <= max_cutoff)) if mask[0].size > 0: pairs = np.c_[mask[0], mask[1]] + else: + pairs = np.empty((0, 2), dtype=np.int64) if return_distances: - distance = distance[mask] - return pairs, distance + distances = distances[mask] + return pairs, distances else: return pairs + @check_coords('reference', 'configuration', enforce_copy=False, reduce_result_if_single=False, check_lengths_match=False) def _pkdtree_capped(reference, configuration, max_cutoff, min_cutoff=None, box=None, return_distances=True): - """ Capped Distance evaluations using KDtree. + """Capped distance evaluations using a KDtree method. - Uses minimum image convention if *box* is specified + Computes and returns an array containing pairs of indices corresponding to + entries in the `reference` and `configuration` arrays which are separated by + a distance lying within the specified cutoff(s). Employs a (periodic) KDtree + algorithm to find relevant distances. - Returns: - -------- - pairs : array - Array of atom indices which are within the specified cutoff distance. - Every pairs `(i, j)` corresponds to i-th particle in reference and - j-th particle in configuration - distance : (optional) array - Distance between two atoms corresponding to the (i, j) indices - in pairs. Only returns when ``return_distances`` - is set to ``True`` + Optionally, these distances can be returned as well. + + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. + + Parameters + ---------- + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)`` (dtype will + be converted to ``numpy.float32`` internally). + configuration : array + Configuration coordinate array with shape ``(3,)`` or ``(m, 3)`` (dtype + will be converted to ``numpy.float32`` internally). + max_cutoff : float + Maximum cutoff distance between `reference` and `configuration` + coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` and `configuration` + coordinates. + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + return_distances : bool, optional + If set to ``True``, distances will also be returned. + Returns + ------- + pairs : numpy.ndarray + Pairs of indices, corresponding to coordinates in the `reference` and + `configuration` arrays such that the distance between them lies within + the interval (`min_cutoff`, `max_cutoff`]. + Each row in `pairs` is an index pair ``[i, j]`` corresponding to the + ``i``-th coordinate in `reference` and the ``j``-th coordinate in + `configuration`. + distances : numpy.ndarray, optional + Distances corresponding to each pair of indices. Only returned if + `return_distances` is ``True``. ``distances[k]`` corresponds to the + ``k``-th pair returned in `pairs` and gives the distance between the + coordinates ``reference[pairs[k, 0]]`` and + ``configuration[pairs[k, 1]]``. """ from .pkdtree import PeriodicKDTree @@ -592,55 +660,73 @@ def _pkdtree_capped(reference, configuration, max_cutoff, min_cutoff=None, pairs = kdtree.search_tree(reference, max_cutoff) if (return_distances or (min_cutoff is not None)) and pairs.size > 0: refA, refB = pairs[:, 0], pairs[:, 1] - distance = calc_bonds(reference[refA], configuration[refB], box=box) + distances = calc_bonds(reference[refA], configuration[refB], box=box) if min_cutoff is not None: - mask = np.where(distance > min_cutoff) - pairs, distance = pairs[mask], distance[mask] + mask = np.where(distances > min_cutoff) + pairs, distances = pairs[mask], distances[mask] else: - distance = [] + distances = np.zeros((0, 1), dtype=np.float64) if return_distances: - return pairs, distance + return pairs, distances else: return pairs + @check_coords('reference', 'configuration', enforce_copy=False, reduce_result_if_single=False, check_lengths_match=False) def _nsgrid_capped(reference, configuration, max_cutoff, min_cutoff=None, box=None, return_distances=True): - """Search all the pairs in *reference* and *configuration* within - a specified distance using Grid Search + """Capped distance evaluations using a grid-based search method. + + Computes and returns an array containing pairs of indices corresponding to + entries in the `reference` and `configuration` arrays which are separated by + a distance lying within the specified cutoff(s). Employs a grid-based search + algorithm to find relevant distances. + Optionally, these distances can be returned as well. + + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. Parameters - ----------- - reference : array - reference coordinates array with shape ``reference.shape = (3,)`` - or ``reference.shape = (len(reference), 3)``. + ---------- + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)`` (dtype will + be converted to ``numpy.float32`` internally). configuration : array - Configuration coordinate array with shape ``reference.shape = (3,)`` - or ``reference.shape = (len(reference), 3)`` + Configuration coordinate array with shape ``(3,)`` or ``(m, 3)`` (dtype + will be converted to ``numpy.float32`` internally). max_cutoff : float - Maximum cutoff distance between the reference and configuration - min_cutoff : (optional) float - Minimum cutoff distance between reference and configuration [None] - box : array - The dimensions, if provided, must be provided in the same - The unitcell dimesions for this system format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: - ``[lx,ly, lz, alpha, beta, gamma]``. Minimum image convention - is applied if the box is provided + Maximum cutoff distance between `reference` and `configuration` + coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` and `configuration` + coordinates. + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + return_distances : bool, optional + If set to ``True``, distances will also be returned. Returns ------- - pairs : array - Array of atom indices which are within the specified cutoff distance. - Every pairs `(i, j)` corresponds to i-th particle in reference and - j-th particle in configuration - distance : (optional) array - Distance between two atoms corresponding to the (i, j) indices - in pairs. Only returns when ``return_distances`` - is set to ``True`` + pairs : numpy.ndarray + Pairs of indices, corresponding to coordinates in the `reference` and + `configuration` arrays such that the distance between them lies within + the interval (`min_cutoff`, `max_cutoff`]. + Each row in `pairs` is an index pair ``[i, j]`` corresponding to the + ``i``-th coordinate in `reference` and the ``j``-th coordinate in + `configuration`. + distances : numpy.ndarray, optional + Distances corresponding to each pair of indices. Only returned if + `return_distances` is ``True``. ``distances[k]`` corresponds to the + ``k``-th pair returned in `pairs` and gives the distance between the + coordinates ``reference[pairs[k, 0]]`` and + ``configuration[pairs[k, 1]]``. """ from .nsgrid import FastNS @@ -689,105 +775,110 @@ def _nsgrid_capped(reference, configuration, max_cutoff, min_cutoff=None, def self_capped_distance(reference, max_cutoff, min_cutoff=None, box=None, method=None): - """Finds all the pairs and respective distances within a specified cutoff - for a configuration *reference* + """Calculates pairs of indices corresponding to entries in the `reference` + array which are separated by a distance lying within the specified + cutoff(s). The respective distances are returned as well. - If a *box* is supplied, then a minimum image convention is used - to evaluate the distances. + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. - An automatic guessing of optimized method to calculate the distances is + An automatic guessing of the optimal method to calculate the distances is included in the function. An optional keyword for the method is also - provided. Users can override the method with this functionality. - Currently pkdtree and bruteforce are implemented. + provided. Users can enforce a particular method with this functionality. + Currently brute force, grid search, and periodic KDtree methods are + implemented. Parameters ----------- - reference : array - reference coordinates array with shape ``reference.shape = (3,)`` - or ``reference.shape = (len(reference), 3)`` + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)``. max_cutoff : float - Maximum cutoff distance to check the neighbors with itself - min_cutoff : (optional) float - Minimum cutoff distance [None] - box : (optional) array or None - The dimensions, if provided, must be provided in the same - The unitcell dimesions for this system format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: - ``[lx,ly, lz, alpha, beta, gamma]``. Minimum image convention - is applied if the box is provided [None] - method : (optional) 'bruteforce' or 'pkdtree' or 'None' - Keyword to override the automatic guessing of method built-in - in the function [None] + Maximum cutoff distance between `reference` coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` coordinates. + box : array_like, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + method : str, optional + Keyword to override the automatic guessing ofthe employed search method. + Can be ``'bruteforce'``, ``'nsgrid'``, or ``'pkdtree'``. Returns ------- - pairs : array - Pair of indices such that distance between them is - within the ``max_cutoff`` and ``min_cutoff`` - distances : array - Distances corresponding to each pair of indices. - d[k] corresponding to the pairs[i,j] gives the distance between - i-th and j-th coordinate in reference + pairs : numpy.ndarray + Pairs of indices, corresponding to coordinates in the `reference` array + such that the distance between them lies within the interval + (`min_cutoff`, `max_cutoff`]. + Each row in `pairs` is an index pair ``[i, j]`` corresponding to the + ``i``-th and the ``j``-th coordinate in `reference`. + distances : numpy.ndarray + Distances corresponding to each pair of indices. ``distances[k]`` + corresponds to the ``k``-th pair returned in `pairs` and gives the + distance between the coordinates ``reference[pairs[k, 0]]`` and + ``reference[pairs[k, 1]]``. .. code-block:: python pairs, distances = self_capped_distances(reference, max_cutoff) - for indx, [a,b] in enumerate(pairs): - coord1, coords2 = reference[a], reference[b] - distance = distances[indx] + for k, [i, j] in enumerate(pairs): + coord1 = reference[i] + coord2 = reference[j] + distance = distances[k] + Note ----- - Currently only supports brute force, Periodic KDtree and Grid Search + Currently supports brute force, grid-based, and periodic KDtree search + methods. - .. SeeAlso:: :func:'MDAnalysis.lib.distances.self_distance_array' - .. SeeAlso:: :func:'MDAnalysis.lib.pkdtree.PeriodicKDTree.search' - .. SeeAlso:: :func:'MDAnalysis.lib.nsgrid.FastNS.self_search' + .. seealso:: :meth:`~MDAnalysis.lib.distances.self_distance_array` + .. seealso:: :meth:`MDAnalysis.lib.pkdtree.PeriodicKDTree.search` + .. seealso:: :meth:`MDAnalysis.lib.nsgrid.FastNS.self_search` """ if box is not None: + box = np.asarray(box, dtype=np.float32) if box.shape[0] != 6: - raise ValueError('Box Argument is of incompatible type. The dimension' - 'should be either None or ' - 'of the type [lx, ly, lz, alpha, beta, gamma]') + raise ValueError("Box Argument is of incompatible type. The " + "dimension should be either None or of the form " + "[lx, ly, lz, alpha, beta, gamma]") method = _determine_method_self(reference, max_cutoff, min_cutoff=min_cutoff, box=box, method=method) - pairs, dist = method(reference, max_cutoff, - min_cutoff=min_cutoff, box=box) + pairs, dist = method(reference, max_cutoff, min_cutoff=min_cutoff, box=box) return np.asarray(pairs), np.asarray(dist) def _determine_method_self(reference, max_cutoff, min_cutoff=None, box=None, method=None): - """ - Switch between different methods based on the the optimized time. - All the rules to select the method based on the input can be - incorporated here. + """Guesses the fastest method for capped distance calculations based on the + size of the `reference` coordinate set and the relative size of the target + volume. Parameters ---------- - reference : array - reference coordinates array with shape ``reference.shape = (3,)`` - or ``reference.shape = (len(reference), 3)`` + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)``. max_cutoff : float - Maximum cutoff distance - min_cutoff : (optional) float - Minimum cutoff distance [None] - box : (optional) array or None - The dimensions, if provided, must be provided in the same - The unitcell dimesions for this system format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: - ``[lx,ly, lz, alpha, beta, gamma]``. Minimum image convention - is applied if the box is provided [None] - method : (optional) 'bruteforce' or 'pkdtree' or 'None' - Keyword to override the automatic guessing of method built-in - in the function [None] + Maximum cutoff distance between `reference` coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` coordinates. + box : numpy.ndarray + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + method : str, optional + Keyword to override the automatic guessing ofthe employed search method. + Can be ``'bruteforce'``, ``'nsgrid'``, or ``'pkdtree'``. Returns ------- - Method : Function object - Returns function object based on the rules and specified method + function : callable + The function implementing the guessed (or deliberatly chosen) method. Note ---- @@ -795,14 +886,13 @@ def _determine_method_self(reference, max_cutoff, min_cutoff=None, box=None, bruteforce : returns ``_bruteforce_capped_self`` PKDtree : return ``_pkdtree_capped_self`` NSGrid : return ``_nsgrid_capped_self`` - """ methods = {'bruteforce': _bruteforce_capped_self, - 'pkdtree': _pkdtree_capped_self, - 'nsgrid': _nsgrid_capped_self} + 'pkdtree': _pkdtree_capped_self, + 'nsgrid': _nsgrid_capped_self} if method is not None: - return methods[method] + return methods[method.lower()] if box is None: min_dim = np.array([reference.min(axis=0)]) @@ -821,23 +911,48 @@ def _determine_method_self(reference, max_cutoff, min_cutoff=None, box=None, else: return methods['nsgrid'] + @check_coords('reference', enforce_copy=False, reduce_result_if_single=False) def _bruteforce_capped_self(reference, max_cutoff, min_cutoff=None, box=None): - """Finds all the pairs among the *reference* coordinates within - a fixed distance using brute force method + """Capped distance evaluations using a brute force method. + + Computes and returns an array containing pairs of indices corresponding to + entries in the `reference` array which are separated by a distance lying + within the specified cutoff(s). Employs naive distance computations (brute + force) to find relevant distances. These distances are returned as well. - Internal method using brute force method to evaluate all the pairs - of atoms within a fixed distance. + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. + + Parameters + ---------- + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)`` (dtype will + be converted to ``numpy.float32`` internally). + max_cutoff : float + Maximum cutoff distance between `reference` coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` coordinates. + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. Returns ------- - pairs : array - Arrray of ``[i, j]`` pairs such that atom-index ``i`` - and ``j`` from reference array are within the fixed distance - distance: array - Distance between ``reference[i]`` and ``reference[j]`` - atom coordinate - + pairs : numpy.ndarray + Pairs of indices, corresponding to coordinates in the `reference` array + such that the distance between them lies within the interval + (`min_cutoff`, `max_cutoff`]. + Each row in `pairs` is an index pair ``[i, j]`` corresponding to the + ``i``-th and the ``j``-th coordinate in `reference`. + distances : numpy.ndarray + Distances corresponding to each pair of indices. ``distances[k]`` + corresponds to the ``k``-th pair returned in `pairs` and gives the + distance between the coordinates ``reference[pairs[k, 0]]`` and + ``reference[pairs[k, 1]]``. """ pairs, distance = [], [] @@ -858,23 +973,48 @@ def _bruteforce_capped_self(reference, max_cutoff, min_cutoff=None, box=None): distance = distance[mask] return np.asarray(pairs), np.asarray(distance) + @check_coords('reference', enforce_copy=False, reduce_result_if_single=False) def _pkdtree_capped_self(reference, max_cutoff, min_cutoff=None, box=None): - """Finds all the pairs among the coordinates within a fixed distance - using PeriodicKDTree + """Capped distance evaluations using a KDtree method. + + Computes and returns an array containing pairs of indices corresponding to + entries in the `reference` array which are separated by a distance lying + within the specified cutoff(s). Employs a (periodic) KDtree algorithm to + find relevant distances. These distances are returned as well. + + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. - Internal method using PeriodicKDTree method to evaluate all the pairs - of atoms within a fixed distance. + Parameters + ---------- + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)`` (dtype will + be converted to ``numpy.float32`` internally). + max_cutoff : float + Maximum cutoff distance between `reference` coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` coordinates. + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. Returns ------- - pairs : array - Array of ``[(i, j)]`` pairs such that atom-index ``i`` - and ``j`` from reference array are within the fixed distance - distance: array - Distance between ``reference[i]`` and ``reference[j]`` - atom coordinate - + pairs : numpy.ndarray + Pairs of indices, corresponding to coordinates in the `reference` array + such that the distance between them lies within the interval + (`min_cutoff`, `max_cutoff`]. + Each row in `pairs` is an index pair ``[i, j]`` corresponding to the + ``i``-th and the ``j``-th coordinate in `reference`. + distances : numpy.ndarray + Distances corresponding to each pair of indices. ``distances[k]`` + corresponds to the ``k``-th pair returned in `pairs` and gives the + distance between the coordinates ``reference[pairs[k, 0]]`` and + ``reference[pairs[k, 1]]``. """ from .pkdtree import PeriodicKDTree @@ -893,18 +1033,45 @@ def _pkdtree_capped_self(reference, max_cutoff, min_cutoff=None, box=None): def _nsgrid_capped_self(reference, max_cutoff, min_cutoff=None, box=None): - """Finds all the pairs among the *reference* coordinates within - a fixed distance using gridsearch + """Capped distance evaluations using a grid-based search method. + + Computes and returns an array containing pairs of indices corresponding to + entries in the `reference` array which are separated by a distance lying + within the specified cutoff(s). Employs a grid-based search algorithm to + find relevant distances. These distances are returned as well. + + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. + + Parameters + ---------- + reference : numpy.ndarray + Reference coordinate array with shape ``(3,)`` or ``(n, 3)`` (dtype will + be converted to ``numpy.float32`` internally). + max_cutoff : float + Maximum cutoff distance between `reference` coordinates. + min_cutoff : float, optional + Minimum cutoff distance between `reference` coordinates. + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. Returns ------- - pairs : array - Arrray of ``[i, j]`` pairs such that atom-index ``i`` - and ``j`` from reference array are within a fixed distance - distance: array - Distance between ``reference[i]`` and ``reference[j]`` - atom coordinate - + pairs : numpy.ndarray + Pairs of indices, corresponding to coordinates in the `reference` array + such that the distance between them lies within the interval + (`min_cutoff`, `max_cutoff`]. + Each row in `pairs` is an index pair ``[i, j]`` corresponding to the + ``i``-th and the ``j``-th coordinate in `reference`. + distances : numpy.ndarray + Distances corresponding to each pair of indices. ``distances[k]`` + corresponds to the ``k``-th pair returned in `pairs` and gives the + distance between the coordinates ``reference[pairs[k, 0]]`` and + ``reference[pairs[k, 1]]``. """ from .nsgrid import FastNS @@ -948,6 +1115,7 @@ def _nsgrid_capped_self(reference, max_cutoff, min_cutoff=None, box=None): pairs, pair_distance = pairs[idx], pair_distance[idx] return pairs, pair_distance + @check_coords('coords') def transform_RtoS(coords, box, backend="serial"): """Transform an array of coordinates from real space to S space (a.k.a. @@ -982,6 +1150,7 @@ def transform_RtoS(coords, box, backend="serial"): Added *backend* keyword. .. versionchanged:: 0.19.0 Internal dtype conversion of input coordinates to ``numpy.float32``. + Now also accepts (and, likewise, returns) a single coordinate. """ boxtype, box = _check_box(box) if boxtype == 'ortho': @@ -1029,6 +1198,7 @@ def transform_StoR(coords, box, backend="serial"): Added *backend* keyword. .. versionchanged:: 0.19.0 Internal dtype conversion of input coordinates to ``numpy.float32``. + Now also accepts (and, likewise, returns) a single coordinate. """ boxtype, box = _check_box(box) if boxtype == 'ortho': @@ -1037,52 +1207,56 @@ def transform_StoR(coords, box, backend="serial"): _run("coord_transform", args=(coords, box), backend=backend) return coords + @check_coords('coords1', 'coords2', enforce_copy=False) def calc_bonds(coords1, coords2, box=None, result=None, backend="serial"): - """ - Calculate all distances between a pair of atoms. *atom1* and *atom2* are both - arrays of coordinates, where atom1[i] and atom2[i] represent a bond. + """Calculates the bond lengths between pairs of atom positions from the two + coordinate arrays `coords1` and `coords2`. Both coordinate arrays must be of + the same length, so that ``coords1[i]`` and ``coords2[i]`` represent the + positions of atoms connected by the ``i``-th bond. - In comparison to distance_array and self_distance_array which calculate distances - between all combinations of coordinates, calc_bonds can be used to calculate distance - between pairs of objects, similar to:: + In comparison to :meth:`distance_array` and :meth:`self_distance_array`, + which calculate distances between all possible combinations of coordinates, + :meth:`calc_bonds` only calculates distances between pairs of coordinates, + similar to:: numpy.linalg.norm(a - b) for a, b in zip(coords1, coords2) - The optional argument *box* applies minimum image convention if supplied. - *box* can be either orthogonal or triclinic + If the optional argument `box` is supplied, the minimum image convention is + applied when calculating distances. Either orthogonal or triclinic boxes are + supported. - If a 1D numpy array of dtype ``numpy.float64`` with ``len(atom1)`` elements is - provided in *result* then this preallocated array is filled. This can speed - up calculations. - - bondlengths = calc_bonds(coords1, coords2 [, box [,result=bondlengths]]) + If a 1D numpy array of dtype ``numpy.float64`` with ``len(coords1)`` + elements is provided in `result`, then this preallocated array is filled. + This can speed up calculations. Parameters ---------- - coords1 : array - An array of coordinates for one half of the bond (``dtype`` is - arbitrary, will be converted to ``dtype=numpy.float32`` internally) - coords2 : array - An array of coordinates for the other half of bond (``dtype`` is - arbitrary, will be converted to ``dtype=numpy.float32`` internally) - box : array - The unitcell dimesions for this system. - The dimensions must be provided in the same format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: ``[lx, - ly, lz, alpha, beta, gamma]``. - result : array, optional - Preallocated result array which must be same length as coord - arrays and ``dtype=numpy.float64``. Avoids creating the - array which saves time when the function is called repeatedly. [None] - backend : str - Select the type of acceleration; "serial" is always available. Other - possibilities are "OpenMP" (OpenMP). + coords1 : numpy.ndarray + Coordinate array of shape ``(n, 3)`` for one half of ``n`` bonds (dtype + is arbitrary, will be converted to ``numpy.float32`` internally). + coords2 : numpy.ndarray + Coordinate array of shape ``(n, 3)`` for the other half of ``n`` bonds + (dtype is arbitrary, will be converted to ``numpy.float32`` internally). + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + result : numpy.ndarray, optional + Preallocated result array which must be of the same length ``n`` as the + coordinate arrays and of dtype ``numpy.float64``. Avoids recreating the + array in repeated function calls. + backend : str, optional + Select the type of acceleration; ``'serial'`` is always available. + Another possibility is ``'OpenMP'``. Returns ------- - bondlengths : array - The length between each pair in coords1 and coords2 + bondlengths : numpy.ndarray or float + Array of dtype ``numpy.float64`` containing the bond lengths between + each pair of coordinates. If two single coordinates were supplied, their + distance is returned as a single number instead of an array. .. versionadded:: 0.8 @@ -1090,6 +1264,7 @@ def calc_bonds(coords1, coords2, box=None, result=None, backend="serial"): Added *backend* keyword. .. versionchanged:: 0.19.0 Internal dtype conversion of input coordinates to ``numpy.float32``. + Now also accepts single coordinates as input. """ numatom = coords1.shape[0] bondlengths = _check_result_array(result, (numatom,)) @@ -1111,60 +1286,76 @@ def calc_bonds(coords1, coords2, box=None, result=None, backend="serial"): return bondlengths + @check_coords('coords1', 'coords2', 'coords3', enforce_copy=False) def calc_angles(coords1, coords2, coords3, box=None, result=None, backend="serial"): - """ - Calculates the angle formed between three atoms, over a list of coordinates. - All *atom* inputs are lists of coordinates of equal length, with *atom2* - representing the apex of the angle. + """Calculates the angles formed between triplets of atom positions from the + three coordinate arrays `coords1`, `coords2`, and `coords3`. All coordinate + arrays must be of equal length, with the coordinates in `coords2` + representing the apices of the angles:: + + 2---3 + / + 1 - If a 1D numpy array of dtype ``numpy.float64`` with ``len(atom1)`` elements is - provided in *result* then this preallocated array is filled. This can speed - up calculations. + Configurations where the angle is undefined (e.g., when coordinates 1 or 3 + of a triplet coincide with coordinate 2) result in a value of zero for that + angle. - The optional argument ``box`` ensures that periodic boundaries are taken into account when - constructing the connecting vectors between atoms, ie that the vector between atoms 1 & 2 - goes between coordinates in the same image. + If the optional argument `box` is supplied, periodic boundaries are taken + into account when constructing the connecting vectors between coordinates, + i.e., the minimum image convention is applied for the vectors forming the + angles. Either orthogonal or triclinic boxes are supported. - angles = calc_angles(coords1, coords2, coords3, [[box=None],result=angles]) + If a 1D numpy array of dtype ``numpy.float64`` with ``len(coords1)`` + elements is provided in `result`, then this preallocated array is filled. + This can speed up calculations. Parameters ---------- coords1 : numpy.ndarray - Coordinate array of one side of angles (``dtype`` is arbitrary, will be - converted to ``dtype=numpy.float32`` internally) + Array of shape ``(n, 3)`` containing the coordinates of one side of + ``n`` angles (dtype is arbitrary, will be converted to ``numpy.float32`` + internally) coords2 : numpy.ndarray - Coordinate array of apex of angles (``dtype`` is arbitrary, will be - converted to ``dtype=numpy.float32`` internally) + Array of shape ``(n, 3)`` containing the coordinates of the apices of + ``n`` angles (dtype is arbitrary, will be converted to ``numpy.float32`` + internally) coords3 : numpy.ndarray - Coordinate array of other side of angles (``dtype`` is arbitrary, will be - converted to ``dtype=numpy.float32`` internally) + Array of shape ``(n, 3)`` containing the coordinates of the other side + of ``n`` angles (dtype is arbitrary, will be converted to + ``numpy.float32`` internally) box : numpy.ndarray, optional - The unitcell dimesions for this system. - The dimensions must be provided in the same format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: ``[lx, - ly, lz, alpha, beta, gamma]``. + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. result : numpy.ndarray, optional - Preallocated result array which must be same length as coord - arrays and ``dtype=numpy.float64``. Avoids creating the - array which saves time when the function is called repeatedly. [None] - backend : str - Select the type of acceleration; "serial" is always available. Other - possibilities are "OpenMP" (OpenMP). + Preallocated result array which must be of the same length ``n`` as the + coordinate arrays and of dtype ``numpy.float64``. Avoids recreating the + array in repeated function calls. + backend : str, optional + Select the type of acceleration; ``'serial'`` is always available. + Another possibility is ``'OpenMP'``. Returns ------- - angles : numpy.ndarray - An array of angles in radians. + angles : numpy.ndarray or float + Array of dtype ``numpy.float64`` containing the angles between each + triplet of coordinates. Values are returned in radians (rad). If three + single coordinates were supplied, the angle is returned as a single + number instead of an array. .. versionadded:: 0.8 .. versionchanged:: 0.9.0 - Added optional box argument to account for periodic boundaries in calculation + Added optional box argument to account for periodic boundaries in + calculation .. versionchanged:: 0.13.0 Added *backend* keyword. .. versionchanged:: 0.19.0 Internal dtype conversion of input coordinates to ``numpy.float32``. + Now also accepts single coordinates as input. """ numatom = coords1.shape[0] angles = _check_result_array(result, (numatom,)) @@ -1186,74 +1377,86 @@ def calc_angles(coords1, coords2, coords3, box=None, result=None, backend="seria return angles + @check_coords('coords1', 'coords2', 'coords3', 'coords4', enforce_copy=False) def calc_dihedrals(coords1, coords2, coords3, coords4, box=None, result=None, backend="serial"): - """ - Calculate the dihedral angle formed by four atoms, over a list of coordinates. + """Calculates the dihedral angles formed between quadruplets of positions + from the four coordinate arrays `coords1`, `coords2`, `coords3`, and + `coords4`, which must be of equal length. - Dihedral angle around axis connecting atoms 1 and 2 (i.e. the angle - between the planes spanned by atoms (0,1,2) and (1,2,3)):: + The dihedral angle formed by a quadruplet of positions (1,2,3,4) is + calculated around the axis connecting positions 2 and 3 (i.e., the angle + between the planes spanned by positions (1,2,3) and (2,3,4)):: - 3 + 4 | - 1-----2 + 2-----3 / - 0 + 1 - If a 1D numpy array of dtype ``numpy.float64`` with ``len(atom1)`` elements - is provided in *result* then this preallocated array is filled. This can - speed up calculations. + If all coordinates lie in the same plane, the cis configuration corresponds + to a dihedral angle of zero, and the trans configuration to :math:`\pi` + radians (180 degrees). Configurations where the dihedral angle is undefined + (e.g., when all coordinates lie on the same straight line) result in a value + of ``nan`` (not a number) for that dihedral. - The optional argument ``box`` ensures that periodic boundaries are taken - into account when constructing the connecting vectors between atoms, ie - that the vector between atoms 1 & 2 goes between coordinates in the same - image:: + If the optional argument `box` is supplied, periodic boundaries are taken + into account when constructing the connecting vectors between coordinates, + i.e., the minimum image convention is applied for the vectors forming the + dihedral angles. Either orthogonal or triclinic boxes are supported. - angles = calc_dihedrals(coords1, coords2, coords3, coords4 [,box=box, result=angles]) + If a 1D numpy array of dtype ``numpy.float64`` with ``len(coords1)`` + elements is provided in `result` then this preallocated array is filled. + This can speed up calculations. Parameters ---------- - coords1 : array - Coordinate array of 1st atom in dihedrals (``dtype`` is arbitrary, will - be converted to ``dtype=numpy.float32`` internally) - coords2 : array - Coordinate array of 2nd atom in dihedrals (``dtype`` is arbitrary, will - be converted to ``dtype=numpy.float32`` internally) - coords3 : array - Coordinate array of 3rd atom in dihedrals (``dtype`` is arbitrary, will - be converted to ``dtype=numpy.float32`` internally) - coords4 : array - Coordinate array of 4th atom in dihedrals (``dtype`` is arbitrary, will - be converted to ``dtype=numpy.float32`` internally) - box : array - The unitcell dimesions for this system. - The dimensions must be provided in the same format as returned - by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`: ``[lx, - ly, lz, alpha, beta, gamma]``. - result : array, optional - Preallocated result array which must be same length as coord - arrays and ``dtype=numpy.float64``. Avoids creating the - array which saves time when the function is called repeatedly. [None] - backend : str - Select the type of acceleration; "serial" is always available. Other - possibilities are "OpenMP" (OpenMP). + coords1 : numpy.ndarray + Coordinate array of 1st positions in dihedrals (dtype is arbitrary, will + be converted to ``numpy.float32`` internally) + coords2 : numpy.ndarray + Coordinate array of 2nd positions in dihedrals (dtype is arbitrary, will + be converted to ``numpy.float32`` internally) + coords3 : numpy.ndarray + Coordinate array of 3rd positions in dihedrals (dtype is arbitrary, will + will be converted to ``numpy.float32`` internally) + coords4 : numpy.ndarray + Coordinate array of 4th positions in dihedrals (dtype is arbitrary, will + be converted to ``numpy.float32`` internally) + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + result : numpy.ndarray, optional + Preallocated result array which must be of the same length as the + coordinate arrays and of dtype ``numpy.float64``. Avoids recreating the + array in repeated function calls. + backend : str, optional + Select the type of acceleration; ``'serial'`` is always available. + Another possibility is ``'OpenMP'``. Returns ------- - angles : array - A numpy.array of angles in radians. + dihedrals : numpy.ndarray or float + Array of dtype ``numpy.float64`` containing the dihedral angles formed + by each quadruplet of coordinates. Values are returned in radians (rad). + If four single coordinates were supplied, the dihedral angle is returned + as a single number instead of an array. .. versionadded:: 0.8 .. versionchanged:: 0.9.0 - Added optional box argument to account for periodic boundaries in calculation + Added optional box argument to account for periodic boundaries in + calculation .. versionchanged:: 0.11.0 Renamed from calc_torsions to calc_dihedrals .. versionchanged:: 0.13.0 Added *backend* keyword. .. versionchanged:: 0.19.0 Internal dtype conversion of input coordinates to ``numpy.float32``. + Now also accepts single coordinates as input. """ numatom = coords1.shape[0] dihedrals = _check_result_array(result, (numatom,)) @@ -1275,6 +1478,7 @@ def calc_dihedrals(coords1, coords2, coords3, coords4, box=None, result=None, return dihedrals + @check_coords('coords') def apply_PBC(coords, box, backend="serial"): """Moves coordinates into the primary unit cell. @@ -1282,8 +1486,8 @@ def apply_PBC(coords, box, backend="serial"): Parameters ---------- coords : numpy.ndarray - Coordinate array of shape ``(n, 3)`` (dtype is arbitrary, will be - converted to ``numpy.float32`` internally). + Coordinate array of shape ``(3,)`` or ``(n, 3)`` (dtype is arbitrary, + will be converted to ``numpy.float32`` internally). box : numpy.ndarray The unitcell dimensions of the system, which can be orthogonal or triclinic and must be provided in the same format as returned by @@ -1305,6 +1509,7 @@ def apply_PBC(coords, box, backend="serial"): Added *backend* keyword. .. versionchanged:: 0.19.0 Internal dtype conversion of input coordinates to ``numpy.float32``. + Now also accepts (and, likewise, returns) single coordinates. """ boxtype, box = _check_box(box) if boxtype == 'ortho': @@ -1318,14 +1523,26 @@ def apply_PBC(coords, box, backend="serial"): def calc_distance(a, b, box=None): - """Distance between a and b + """Calculates the distance between positions `a` and `b`. + + If the optional argument `box` is supplied, the minimum image convention is + applied during distance calculation. Either orthogonal or triclinic boxes + are supported. Parameters ---------- - a, b : numpy.ndarray - single coordinate vectors + a,b : numpy.ndarray + Single position vectors of shape ``(3,)``. box : numpy.ndarray, optional - simulation box, if given periodic boundary conditions will be applied + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + + Returns + ------- + distance : float + The distance between positions `a` and `b`. .. versionadded:: 0.18.1 @@ -1334,15 +1551,33 @@ def calc_distance(a, b, box=None): def calc_angle(a, b, c, box=None): - """Angle (in degrees) between a, b and c, where b is apex of angle + """Calculates the angle (in degrees) between the positions `a`, `b`, and + `c`, where `b` represents the apex of the angle:: + + b---c + / + a + + If the optional argument `box` is supplied, periodic boundaries are taken + into account when constructing the connecting vectors between coordinates, + i.e., the minimum image convention is applied for the vectors forming the + angle. Either orthogonal or triclinic boxes are supported. Parameters ---------- - a, b, c : numpy.ndarray - single coordinate vectors - box : numpy.ndarray - simulation box if given periodic boundary conditions will be applied to - the vectors between atoms + a,b,c : numpy.ndarray + Single position vectors of shape ``(3,)``. + box : numpy.ndarray, optional + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + + Returns + ------- + angle : float + The angle between the vectors `b`:math:`\\rightarrow`\ `a` and + `b`:math:`\\rightarrow`\ `c`. .. versionadded:: 0.18.1 @@ -1351,14 +1586,35 @@ def calc_angle(a, b, c, box=None): def calc_dihedral(a, b, c, d, box=None): - """Dihedral angle (in degrees) between planes (a, b, c) and (b, c, d) + """Calculates the dihedral angle (in degrees) between the planes spanned by + the coordinates (`a`, `b`, `c`) and (`b`, `c`, `d`):: + + d + | + b-----c + / + a + + If the optional argument `box` is supplied, periodic boundaries are taken + into account when constructing the connecting vectors between coordinates, + i.e., the minimum image convention is applied for the vectors forming the + dihedral angle. Either orthogonal or triclinic boxes are supported. Parameters ---------- - a, b, c, d : numpy.ndarray - single coordinate vectors + a,b,c,d : numpy.ndarray + Single coordinate vectors of shape ``(3,)``. box : numpy.ndarray, optional - simulation box, if given periodic boundary conditions will be applied + The unitcell dimensions of the system, which can be orthogonal or + triclinic and must be provided in the same format as returned by + :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n + ``[lx, ly, lz, alpha, beta, gamma]``. + + Returns + ------- + dihedral : float + The dihedral angle between the planes spanned by the coordinates + (`a`, `b`, `c`) and (`b`, `c`, `d`). .. versionadded:: 0.18.1 From 73ef0ebbca8bfcb83de524a4dce81cb2dbe3c0c7 Mon Sep 17 00:00:00 2001 From: zeman Date: Wed, 12 Sep 2018 11:46:44 +0200 Subject: [PATCH 07/10] added back autofunction entries in MDAnalysis/lib/distances.py and removed :embers: in doc/sphinx/source/documentation_pages/lib/distances.rst instead --- package/MDAnalysis/lib/distances.py | 13 +++++++++++++ .../source/documentation_pages/lib/distances.rst | 3 +-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index 2e646d9bf14..b45a3a65a25 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -52,6 +52,19 @@ Functions --------- +.. autofunction:: distance_array +.. autofunction:: self_distance_array +.. autofunction:: capped_distance +.. autofunction:: self_capped_distance +.. autofunction:: calc_bonds +.. autofunction:: calc_angles +.. autofunction:: calc_dihedrals +.. autofunction:: calc_distance +.. autofunction:: calc_angle +.. autofunction:: calc_dihedral +.. autofunction:: apply_PBC +.. autofunction:: transform_RtoS +.. autofunction:: transform_StoR .. autofunction:: augment_coordinates(coordinates, box, r) .. autofunction:: undo_augment(results, translation, nreal) """ diff --git a/package/doc/sphinx/source/documentation_pages/lib/distances.rst b/package/doc/sphinx/source/documentation_pages/lib/distances.rst index 8d89a94b09c..c50b85bd1c6 100644 --- a/package/doc/sphinx/source/documentation_pages/lib/distances.rst +++ b/package/doc/sphinx/source/documentation_pages/lib/distances.rst @@ -1,5 +1,4 @@ .. automodule:: MDAnalysis.lib.distances - :members: @@ -16,4 +15,4 @@ the OpenMP-enable functions. :maxdepth: 1 c_distances - c_distances_openmp \ No newline at end of file + c_distances_openmp From 791ecd970eece2ec763cec502efdfae6a0c8adb4 Mon Sep 17 00:00:00 2001 From: zeman Date: Wed, 12 Sep 2018 11:48:50 +0200 Subject: [PATCH 08/10] use numpydoc `See Also` sections instead of `.. seealso::` --- package/MDAnalysis/lib/distances.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index b45a3a65a25..75b04cb78c7 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -163,7 +163,11 @@ def _check_box(box): If `box` is not of the form ``[lx, ly, lz, alpha, beta, gamma]`` or contains data that is not convertible to ``numpy.float32``. - .. seealso: :meth:`MDAnalysis.lib.mdamath.triclinic_vectors` + See Also + -------- + MDAnalysis.lib.mdamath.triclinic_vectors + + .. versionchanged: 0.19.0 * Enforced correspondence of `box` with specified format. * Added automatic conversion of input to :class:`numpy.ndarray` with @@ -441,9 +445,11 @@ def capped_distance(reference, configuration, max_cutoff, min_cutoff=None, Currently supports brute force, grid-based, and periodic KDtree search methods. - .. seealso:: :meth:`~MDAnalysis.lib.distances.distance_array` - .. seealso:: :meth:`MDAnalysis.lib.pkdtree.PeriodicKDTree.search` - .. seealso:: :meth:`MDAnalysis.lib.nsgrid.FastNS.search` + See Also + -------- + distance_array + MDAnalysis.lib.pkdtree.PeriodicKDTree.search + MDAnalysis.lib.nsgrid.FastNS.search """ if box is not None: box = np.asarray(box, dtype=np.float32) @@ -847,9 +853,11 @@ def self_capped_distance(reference, max_cutoff, min_cutoff=None, box=None, Currently supports brute force, grid-based, and periodic KDtree search methods. - .. seealso:: :meth:`~MDAnalysis.lib.distances.self_distance_array` - .. seealso:: :meth:`MDAnalysis.lib.pkdtree.PeriodicKDTree.search` - .. seealso:: :meth:`MDAnalysis.lib.nsgrid.FastNS.self_search` + See Also + -------- + self_distance_array + MDAnalysis.lib.pkdtree.PeriodicKDTree.search + MDAnalysis.lib.nsgrid.FastNS.self_search """ if box is not None: box = np.asarray(box, dtype=np.float32) From c9567dc5399f8a0ab1bff27e7576dc8c07495a46 Mon Sep 17 00:00:00 2001 From: zeman Date: Wed, 12 Sep 2018 11:52:18 +0200 Subject: [PATCH 09/10] numpydoc selections for parameters with fixed value sets --- package/MDAnalysis/lib/distances.py | 64 +++++++++++++---------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index 75b04cb78c7..47299e5a2df 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -262,9 +262,8 @@ def distance_array(reference, configuration, box=None, result=None, ``numpy.float64``. Avoids creating the array which saves time when the function is called repeatedly. - backend : str, optional - Select the type of acceleration; ``'serial'`` is always available. - Another possibility is ``'OpenMP'``. + backend : {'serial', 'OpenMP'}, optional + Keyword selecting the type of acceleration. Returns ------- @@ -328,9 +327,8 @@ def self_distance_array(reference, box=None, result=None, backend="serial"): Preallocated result array which must have the shape ``(n*(n-1)/2,)`` and dtype ``numpy.float64``. Avoids creating the array which saves time when the function is called repeatedly. - backend : str, optional - Select the type of acceleration; ``'serial'`` is always available. - Another possibility is ``'OpenMP'``. + backend : {'serial', 'OpenMP'}, optional + Keyword selecting the type of acceleration. Returns ------- @@ -409,9 +407,9 @@ def capped_distance(reference, configuration, max_cutoff, min_cutoff=None, triclinic and must be provided in the same format as returned by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n ``[lx, ly, lz, alpha, beta, gamma]``. - method : str, optional - Keyword to override the automatic guessing ofthe employed search method. - Can be ``'bruteforce'``, ``'nsgrid'``, or ``'pkdtree'``. + method : {'bruteforce', 'nsgrid', 'pkdtree'}, optional + Keyword to override the automatic guessing of the employed search + method. return_distances : bool, optional If set to ``True``, distances will also be returned. @@ -496,9 +494,9 @@ def _determine_method(reference, configuration, max_cutoff, min_cutoff=None, triclinic and must be provided in the same format as returned by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n ``[lx, ly, lz, alpha, beta, gamma]``. - method : str, optional - Keyword to override the automatic guessing ofthe employed search method. - Can be ``'bruteforce'``, ``'nsgrid'``, or ``'pkdtree'``. + method : {'bruteforce', 'nsgrid', 'pkdtree'}, optional + Keyword to override the automatic guessing of the employed search + method. Returns ------- @@ -821,9 +819,9 @@ def self_capped_distance(reference, max_cutoff, min_cutoff=None, box=None, triclinic and must be provided in the same format as returned by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n ``[lx, ly, lz, alpha, beta, gamma]``. - method : str, optional - Keyword to override the automatic guessing ofthe employed search method. - Can be ``'bruteforce'``, ``'nsgrid'``, or ``'pkdtree'``. + method : {'bruteforce', 'nsgrid', 'pkdtree'}, optional + Keyword to override the automatic guessing of the employed search + method. Returns ------- @@ -892,9 +890,9 @@ def _determine_method_self(reference, max_cutoff, min_cutoff=None, box=None, triclinic and must be provided in the same format as returned by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n ``[lx, ly, lz, alpha, beta, gamma]``. - method : str, optional - Keyword to override the automatic guessing ofthe employed search method. - Can be ``'bruteforce'``, ``'nsgrid'``, or ``'pkdtree'``. + method : {'bruteforce', 'nsgrid', 'pkdtree'}, optional + Keyword to override the automatic guessing of the employed search + method. Returns ------- @@ -1156,9 +1154,8 @@ def transform_RtoS(coords, box, backend="serial"): triclinic and must be provided in the same format as returned by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n ``[lx, ly, lz, alpha, beta, gamma]``. - backend : str, optional - Select the type of acceleration; ``'serial'`` is always available. - Another possibility is ``'OpenMP'``. + backend : {'serial', 'OpenMP'}, optional + Keyword selecting the type of acceleration. Returns ------- @@ -1204,9 +1201,8 @@ def transform_StoR(coords, box, backend="serial"): triclinic and must be provided in the same format as returned by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n ``[lx, ly, lz, alpha, beta, gamma]``. - backend : str, optional - Select the type of acceleration; ``'serial'`` is always available. - Another possibility is ``'OpenMP'``. + backend : {'serial', 'OpenMP'}, optional + Keyword selecting the type of acceleration. Returns ------- @@ -1268,9 +1264,8 @@ def calc_bonds(coords1, coords2, box=None, result=None, backend="serial"): Preallocated result array which must be of the same length ``n`` as the coordinate arrays and of dtype ``numpy.float64``. Avoids recreating the array in repeated function calls. - backend : str, optional - Select the type of acceleration; ``'serial'`` is always available. - Another possibility is ``'OpenMP'``. + backend : {'serial', 'OpenMP'}, optional + Keyword selecting the type of acceleration. Returns ------- @@ -1355,9 +1350,8 @@ def calc_angles(coords1, coords2, coords3, box=None, result=None, backend="seria Preallocated result array which must be of the same length ``n`` as the coordinate arrays and of dtype ``numpy.float64``. Avoids recreating the array in repeated function calls. - backend : str, optional - Select the type of acceleration; ``'serial'`` is always available. - Another possibility is ``'OpenMP'``. + backend : {'serial', 'OpenMP'}, optional + Keyword selecting the type of acceleration. Returns ------- @@ -1454,9 +1448,8 @@ def calc_dihedrals(coords1, coords2, coords3, coords4, box=None, result=None, Preallocated result array which must be of the same length as the coordinate arrays and of dtype ``numpy.float64``. Avoids recreating the array in repeated function calls. - backend : str, optional - Select the type of acceleration; ``'serial'`` is always available. - Another possibility is ``'OpenMP'``. + backend : {'serial', 'OpenMP'}, optional + Keyword selecting the type of acceleration. Returns ------- @@ -1514,9 +1507,8 @@ def apply_PBC(coords, box, backend="serial"): triclinic and must be provided in the same format as returned by :attr:`MDAnalysis.coordinates.base.Timestep.dimensions`:\n ``[lx, ly, lz, alpha, beta, gamma]``. - backend : str, optional - Select the type of acceleration; ``'serial'`` is always available. - Another possibility is ``'OpenMP'``. + backend : {'serial', 'OpenMP'}, optional + Keyword selecting the type of acceleration. Returns ------- From 4caeea27ce6e5f1d5397fbcd43adc111d2d0e77f Mon Sep 17 00:00:00 2001 From: zeman Date: Wed, 12 Sep 2018 14:38:04 +0200 Subject: [PATCH 10/10] moved nsgrid import to top of lib/distances.py --- package/MDAnalysis/lib/distances.py | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index 47299e5a2df..a512d8ef0d2 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -77,8 +77,7 @@ from .util import check_coords from .mdamath import triclinic_vectors, triclinic_box from ._augment import augment_coordinates, undo_augment - - +from .nsgrid import FastNS # hack to select backend with backend= kwarg. Note that # the cython parallel code (prange) in parallel.distances is @@ -502,13 +501,6 @@ def _determine_method(reference, configuration, max_cutoff, min_cutoff=None, ------- function : callable The function implementing the guessed (or deliberatly chosen) method. - - Note - ---- - Currently implemented methods are present in the ``methods`` dictionary - bruteforce : returns ``_bruteforce_capped`` - PKDtree : return ``_pkdtree_capped`` - NSGrid : return ``_nsgrid_capped`` """ methods = {'bruteforce': _bruteforce_capped, 'pkdtree': _pkdtree_capped, @@ -669,7 +661,7 @@ def _pkdtree_capped(reference, configuration, max_cutoff, min_cutoff=None, coordinates ``reference[pairs[k, 0]]`` and ``configuration[pairs[k, 1]]``. """ - from .pkdtree import PeriodicKDTree + from .pkdtree import PeriodicKDTree # must be here to avoid circular import kdtree = PeriodicKDTree(box=box) cut = max_cutoff if box is not None else None @@ -745,8 +737,6 @@ def _nsgrid_capped(reference, configuration, max_cutoff, min_cutoff=None, coordinates ``reference[pairs[k, 0]]`` and ``configuration[pairs[k, 1]]``. """ - from .nsgrid import FastNS - if box is None: # create a pseudobox # define the max range @@ -898,13 +888,6 @@ def _determine_method_self(reference, max_cutoff, min_cutoff=None, box=None, ------- function : callable The function implementing the guessed (or deliberatly chosen) method. - - Note - ---- - Currently implemented methods are present in the ``methods`` dictionary - bruteforce : returns ``_bruteforce_capped_self`` - PKDtree : return ``_pkdtree_capped_self`` - NSGrid : return ``_nsgrid_capped_self`` """ methods = {'bruteforce': _bruteforce_capped_self, 'pkdtree': _pkdtree_capped_self, @@ -1035,7 +1018,7 @@ def _pkdtree_capped_self(reference, max_cutoff, min_cutoff=None, box=None): distance between the coordinates ``reference[pairs[k, 0]]`` and ``reference[pairs[k, 1]]``. """ - from .pkdtree import PeriodicKDTree + from .pkdtree import PeriodicKDTree # must be here to avoid circular import pairs, distance = [], [] kdtree = PeriodicKDTree(box=box) @@ -1092,8 +1075,6 @@ def _nsgrid_capped_self(reference, max_cutoff, min_cutoff=None, box=None): distance between the coordinates ``reference[pairs[k, 0]]`` and ``reference[pairs[k, 1]]``. """ - from .nsgrid import FastNS - reference = np.asarray(reference, dtype=np.float32) if reference.shape == (3, ) or len(reference) == 1: return [], []