Source code for spatula.util

# Copyright (c) 2021-2026 The Regents of the University of Michigan
# Part of spatula, released under the BSD 3-Clause License.

"""General utility functions for the package and users."""

import collections
import operator

import numpy as np

from . import _spatula_nb, freud

PI_2 = np.pi / 2
PI_4 = np.pi / 4


[docs] def sph_to_cart(theta, phi): r"""Convert spherical to Cartesian coordinates on the unit sphere. Parameters ---------- theta: :math:`(N,)` numpy.ndarray of float The longitudinal (polar) angle from :math:`[0, \pi]`. phi : :math:`(N,)` numpy.ndarray of float The latitudinal (azimuthal) angle from :math:`[0, 2 \pi]`. Returns ------- coords : :math:`(N, 3)` numpy.ndarray of float The Cartesian coordinates of the points. """ x = np.empty(theta.shape + (3,)) sin_theta = np.sin(theta) x[..., 0] = sin_theta * np.cos(phi) x[..., 1] = sin_theta * np.sin(phi) x[..., 2] = np.cos(theta) return x
[docs] def set_num_threads(num_threads): """Set the number of threads to use when computing PGOP. Parameters ---------- num_threads : int The number of threads. """ if num_threads < 1: raise ValueError("Must set to a positive number of threads.") try: num_threads = int(num_threads) except ValueError as err: raise ValueError("num_threads must be convertible to an int") from err _spatula_nb.set_num_threads(num_threads) freud.parallel.set_num_threads(num_threads)
[docs] def get_num_threads(): """Get the number of threads used when computing PGOP. Returns ------- num_threads : int The number of threads. """ return _spatula_nb.get_num_threads()
class _Cache: """A simple cache that supports a maximum size. Size restraints by removing the least frequently used keys. The cache also supports preventing deleting the most recently used keys as well through a FIFO stack. """ def __init__(self, max_size=None, keep_n_most_recent=1): """Construct a cache object. Parameters ---------- max_size : int, optional The maximum size for the cache. Defaults to ``None`` which means no limit on cache size. keep_n_most_recent : int, optional The number of recent examples to not allow for removal regardless of popularity. Defaults to 1 key. """ self._data = {} self._key_counts = collections.Counter() self._recent_keys = collections.deque(maxlen=keep_n_most_recent) self.max_size = max_size def __contains__(self, key): """Return whether the given key is in the cache.""" return key in self._data def __getitem__(self, key): """Get the cached value for key and error if not present.""" data = self._data.get(key, None) if data is None: return data if self.max_size is not None: self._recent_keys.append(key) self._key_counts[key] += 1 return data def __setitem__(self, key, data): """Set the cached value for key overwriting if necessary.""" self._data[key] = data if self.max_size is None: return if len(self._data) > self.max_size: removal_order = sorted(self._key_counts, key=operator.itemgetter(1)) for k, _ in removal_order: if k not in self._recent_keys: del self._data[k] break