diff --git a/freud/CMakeLists.txt b/freud/CMakeLists.txt index 1c00f3f7b..5cfaccaab 100644 --- a/freud/CMakeLists.txt +++ b/freud/CMakeLists.txt @@ -20,10 +20,10 @@ add_library( # box box/Box.h # cluster - # cluster/Cluster.h - # cluster/Cluster.cc - # cluster/ClusterProperties.h - # cluster/ClusterProperties.cc + cluster/Cluster.h + cluster/Cluster.cc + cluster/ClusterProperties.h + cluster/ClusterProperties.cc # density # density/CorrelationFunction.h # density/CorrelationFunction.cc @@ -133,9 +133,12 @@ set_target_properties(freud PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(freud PUBLIC TBB::tbb) target_include_directories(freud SYSTEM PUBLIC ${PROJECT_SOURCE_DIR}/extern/) -# cluster nanobind_add_module(_cluster cluster/...) -# target_link_libraries(_cluster PUBLIC freud TBB::tbb) -# target_set_install_rpath(_cluster) +# cluster +nanobind_add_module( + _cluster cluster/module-Cluster.cc cluster/export-Cluster.cc + cluster/export-ClusterProperties.cc) +target_link_libraries(_cluster PUBLIC freud TBB::tbb) +target_set_install_rpath(_cluster) # density nanobind_add_module(_density density/...) # target_link_libraries(_density PUBLIC freud TBB::tbb) @@ -193,6 +196,7 @@ target_set_install_rpath(_util) set(python_files __init__.py box.py + cluster.py data.py errors.py locality.py @@ -202,7 +206,7 @@ set(python_files interface.py plot.py util.py) -# cluster.py density.py diffraction.py environment.py order.py interface.py) +# density.py diffraction.py environment.py order.py) copy_files_to_build("${python_files}" "freud" "*.py") @@ -210,9 +214,9 @@ copy_files_to_build("${python_files}" "freud" "*.py") if(SKBUILD) install(FILES ${python_files} DESTINATION freud) install(TARGETS _box DESTINATION freud) - # install(TARGETS _cluster DESTINATION freud) install(TARGETS _density - # DESTINATION freud) install(TARGETS _diffraction DESTINATION freud) - # install(TARGETS _environment DESTINATION freud) + install(TARGETS _cluster DESTINATION freud) + # install(TARGETS _density DESTINATION freud) install(TARGETS _diffraction + # DESTINATION freud) install(TARGETS _environment DESTINATION freud) install(TARGETS _locality DESTINATION freud) # install(TARGETS _order DESTINATION freud) install(TARGETS _parallel DESTINATION freud) diff --git a/freud/__init__.py b/freud/__init__.py index 0bb453597..f8d9f4809 100644 --- a/freud/__init__.py +++ b/freud/__init__.py @@ -1,9 +1,8 @@ # Copyright (c) 2010-2024 The Regents of the University of Michigan # This file is from the freud project, released under the BSD 3-Clause License. - -# cluster,; density,; diffraction,; environment,; interface,; msd,; order, -from . import box, data, interface, locality, msd, parallel, pmft +# density,; diffraction,; environment,; order, +from . import box, cluster, data, interface, locality, msd, parallel, pmft from .box import Box from .locality import AABBQuery, LinkCell, NeighborList from .parallel import NumThreads, get_num_threads, set_num_threads @@ -17,7 +16,7 @@ __all__ = [ "__version__", "box", - # "cluster", + "cluster", "data", # "density", # "diffraction", diff --git a/freud/cluster.pyx b/freud/cluster.py similarity index 69% rename from freud/cluster.pyx rename to freud/cluster.py index 8575eefd4..48ffa855d 100644 --- a/freud/cluster.pyx +++ b/freud/cluster.py @@ -6,27 +6,16 @@ of clusters of points in a system. """ -from cython.operator cimport dereference - -from freud.locality cimport _PairCompute -from freud.util cimport _Compute - import numpy as np +import freud._cluster import freud.locality import freud.util +from freud.locality import _PairCompute +from freud.util import _Compute -cimport numpy as np - -cimport freud._cluster -cimport freud.locality -cimport freud.util - -# numpy must be initialized. When using numpy from C or Cython you must -# _always_ do that, or you will have segfaults -np.import_array() -cdef class Cluster(_PairCompute): +class Cluster(_PairCompute): """Finds clusters using a network of neighbors. Given a set of points and their neighbors, :class:`freud.cluster.Cluster` @@ -50,16 +39,8 @@ :code:`cluster_keys` contains the point ids present in each cluster. """ - cdef freud._cluster.Cluster * thisptr - - def __cinit__(self): - self.thisptr = new freud._cluster.Cluster() - def __init__(self): - pass - - def __dealloc__(self): - del self.thisptr + self._cpp_obj = freud._cluster.Cluster() def compute(self, system, keys=None, neighbors=None): r"""Compute the clusters for the given set of points. @@ -77,52 +58,36 @@ def compute(self, system, keys=None, neighbors=None): `_ (Default value: None). """ - cdef: - freud.locality.NeighborQuery nq - freud.locality.NeighborList nlist - freud.locality._QueryArgs qargs - const float[:, ::1] l_query_points - unsigned int num_query_points - - nq, nlist, qargs, l_query_points, num_query_points = \ - self._preprocess_arguments(system, neighbors=neighbors) - - cdef unsigned int* l_keys_ptr = NULL - cdef unsigned int[::1] l_keys + nq, nlist, qargs, query_points, num_query_points = self._preprocess_arguments( + system, neighbors=neighbors + ) if keys is not None: - l_keys = freud.util._convert_array( - keys, shape=(num_query_points, ), dtype=np.uint32) - l_keys_ptr = &l_keys[0] - - self.thisptr.compute( - nq.get_ptr(), - nlist.get_ptr(), - dereference(qargs.thisptr), - l_keys_ptr) + keys = freud.util._convert_array( + keys, shape=(num_query_points,), dtype=np.uint32 + ) + + self._cpp_obj.compute(nq._cpp_obj, nlist._cpp_obj, qargs._cpp_obj, keys) return self @_Compute._computed_property def num_clusters(self): """int: The number of clusters.""" - return self.thisptr.getNumClusters() + return self._cpp_obj.getNumClusters() @_Compute._computed_property def cluster_idx(self): """(:math:`N_{points}`) :class:`numpy.ndarray`: The cluster index for each point.""" - return freud.util.make_managed_numpy_array( - &self.thisptr.getClusterIdx(), - freud.util.arr_type_t.UNSIGNED_INT) + return self._cpp_obj.getClusterIdx().toNumpyArray() @_Compute._computed_property def cluster_keys(self): """list(list): A list of lists of the keys contained in each cluster.""" - cluster_keys = self.thisptr.getClusterKeys() - return cluster_keys + return self._cpp_obj.getClusterKeys() def __repr__(self): - return "freud.cluster.{cls}()".format(cls=type(self).__name__) + return f"freud.cluster.{type(self).__name__}()" def plot(self, ax=None): """Plot cluster distribution. @@ -136,49 +101,42 @@ def plot(self, ax=None): (:class:`matplotlib.axes.Axes`): Axis with the plot. """ import freud.plot + try: values, counts = np.unique(self.cluster_idx, return_counts=True) except ValueError: return None - return freud.plot.clusters_plot( - values, counts, num_clusters_to_plot=10, ax=ax) + return freud.plot.clusters_plot(values, counts, num_clusters_to_plot=10, ax=ax) def _repr_png_(self): try: import freud.plot + return freud.plot._ax_to_bytes(self.plot()) except (AttributeError, ImportError): return None -cdef class ClusterProperties(_Compute): +class ClusterProperties(_Compute): r"""Routines for computing properties of point clusters. Given a set of points and cluster ids (from :class:`~.Cluster` or another source), this class determines the following properties for each cluster: - - Geometric center - - Center of mass - - Gyration tensor - - Moment of inertia tensor - - Size (number of points) - - Mass (total mass of each cluster) + - Geometric center + - Center of mass + - Gyration tensor + - Moment of inertia tensor + - Size (number of points) + - Mass (total mass of each cluster) Note: The center of mass and geometric center for each cluster are computed using the minimum image convention """ - cdef freud._cluster.ClusterProperties * thisptr - - def __cinit__(self): - self.thisptr = new freud._cluster.ClusterProperties() - def __init__(self): - pass - - def __dealloc__(self): - del self.thisptr + self._cpp_obj = freud._cluster.ClusterProperties() def compute(self, system, cluster_idx, masses=None): r"""Compute properties of the point clusters. @@ -210,21 +168,14 @@ def compute(self, system, cluster_idx, masses=None): Masses corresponding to each point, defaulting to 1 if not provided or :code:`None` (Default value = :code:`None`). """ - cdef freud.locality.NeighborQuery nq = \ - freud.locality.NeighborQuery.from_system(system) - cluster_idx = freud.util._convert_array( - cluster_idx, shape=(nq.points.shape[0], ), dtype=np.uint32) - cdef const unsigned int[::1] l_cluster_idx = cluster_idx + nq = freud.locality.NeighborQuery.from_system(system) - cdef float* l_masses_ptr = NULL - cdef float[::1] l_masses + cluster_idx = freud.util._convert_array( + cluster_idx, shape=(nq.points.shape[0],), dtype=np.uint32 + ) if masses is not None: - l_masses = freud.util._convert_array(masses, shape=(len(masses), )) - l_masses_ptr = &l_masses[0] - - self.thisptr.compute(nq.get_ptr(), - &l_cluster_idx[0], - l_masses_ptr) + masses = freud.util._convert_array(masses, shape=(len(masses),)) + self._cpp_obj.compute(nq._cpp_obj, cluster_idx, masses) return self @_Compute._computed_property @@ -240,9 +191,7 @@ def centers(self): :math:`N_k` is the number of particles in the :math:`k` th cluster and :math:`\mathbf{r_i}` are their positions. """ - return freud.util.make_managed_numpy_array( - &self.thisptr.getClusterCenters(), - freud.util.arr_type_t.FLOAT, 3) + return self._cpp_obj.getClusterCenters().toNumpyArray() @_Compute._computed_property def centers_of_mass(self): @@ -258,9 +207,7 @@ def centers_of_mass(self): cluster, :math:`\mathbf{r_i}` are their positions and :math:`m_i` are their masses. """ - return freud.util.make_managed_numpy_array( - &self.thisptr.getClusterCentersOfMass(), - freud.util.arr_type_t.FLOAT, 3) + return self._cpp_obj.getClusterCentersOfMass().toNumpyArray() @_Compute._computed_property def gyrations(self): @@ -278,9 +225,7 @@ def gyrations(self): where :math:`\mathbf{S}_k` is the gyration tensor of the :math:`k` th cluster. """ - return freud.util.make_managed_numpy_array( - &self.thisptr.getClusterGyrations(), - freud.util.arr_type_t.FLOAT) + return self._cpp_obj.getClusterGyrations().toNumpyArray() @_Compute._computed_property def inertia_tensors(self): @@ -298,25 +243,19 @@ def inertia_tensors(self): where :math:`\mathbf{I}_k` is the inertia tensor of the :math:`k` th cluster. """ - return freud.util.make_managed_numpy_array( - &self.thisptr.getClusterMomentsOfInertia(), - freud.util.arr_type_t.FLOAT) + return self._cpp_obj.getClusterMomentsOfInertia().toNumpyArray() @_Compute._computed_property def sizes(self): """(:math:`N_{clusters}`) :class:`numpy.ndarray`: The cluster sizes.""" - return freud.util.make_managed_numpy_array( - &self.thisptr.getClusterSizes(), - freud.util.arr_type_t.UNSIGNED_INT) + return self._cpp_obj.getClusterSizes().toNumpyArray() @_Compute._computed_property def cluster_masses(self): """(:math:`N_{clusters}`) :class:`numpy.ndarray`: The total mass of particles in each cluster. """ - return freud.util.make_managed_numpy_array( - &self.thisptr.getClusterMasses(), - freud.util.arr_type_t.FLOAT) + return self._cpp_obj.getClusterMasses().toNumpyArray() @_Compute._computed_property def radii_of_gyration(self): @@ -331,8 +270,10 @@ def radii_of_gyration(self): the center of mass. """ - return np.sqrt(np.trace(self.inertia_tensors, axis1=-2, axis2=-1) - /(2*self.cluster_masses)) + return np.sqrt( + np.trace(self.inertia_tensors, axis1=-2, axis2=-1) + / (2 * self.cluster_masses) + ) def __repr__(self): - return "freud.cluster.{cls}()".format(cls=type(self).__name__) + return f"freud.cluster.{type(self).__name__}()" diff --git a/freud/cluster/Cluster.cc b/freud/cluster/Cluster.cc index cf31ddc58..f1e2fb95a 100644 --- a/freud/cluster/Cluster.cc +++ b/freud/cluster/Cluster.cc @@ -12,11 +12,12 @@ //! Finds clusters using a network of neighbors. namespace freud { namespace cluster { -void Cluster::compute(const freud::locality::NeighborQuery* nq, const freud::locality::NeighborList* nlist, - freud::locality::QueryArgs qargs, const unsigned int* keys) +void Cluster::compute(const std::shared_ptr nq, + const std::shared_ptr nlist, const locality::QueryArgs& qargs, + const unsigned int* keys) { const unsigned int num_points = nq->getNPoints(); - m_cluster_idx.prepare(num_points); + m_cluster_idx = std::make_shared>(num_points); DisjointSets dj(num_points); freud::locality::loopOverNeighbors( @@ -80,7 +81,7 @@ void Cluster::compute(const freud::locality::NeighborQuery* nq, const freud::loc { size_t s = dj.find(i); size_t cluster_idx = cluster_reindex[cluster_label[s]]; - m_cluster_idx[i] = cluster_idx; + (*m_cluster_idx)[i] = cluster_idx; unsigned int key = i; if (keys != nullptr) { diff --git a/freud/cluster/Cluster.h b/freud/cluster/Cluster.h index cf6502424..2f45abde6 100644 --- a/freud/cluster/Cluster.h +++ b/freud/cluster/Cluster.h @@ -44,9 +44,8 @@ class Cluster Cluster() = default; //! Compute the point clusters. - void compute(const freud::locality::NeighborQuery* nq, const freud::locality::NeighborList* nlist, - freud::locality::QueryArgs qargs, const unsigned int* keys = nullptr); - + void compute(std::shared_ptr nq, std::shared_ptr nlist, + const locality::QueryArgs& qargs, const unsigned int* keys = nullptr); //! Get the total number of clusters. unsigned int getNumClusters() const { @@ -54,7 +53,7 @@ class Cluster } //! Get a reference to the cluster ids. - const util::ManagedArray& getClusterIdx() const + std::shared_ptr> getClusterIdx() const { return m_cluster_idx; } @@ -66,9 +65,9 @@ class Cluster } private: - unsigned int m_num_clusters; //!< Number of clusters found - util::ManagedArray m_cluster_idx; //!< Cluster index for each point - std::vector> m_cluster_keys; //!< List of keys in each cluster + unsigned int m_num_clusters; //!< Number of clusters found + std::shared_ptr> m_cluster_idx; //!< Cluster index for each point + std::vector> m_cluster_keys; //!< List of keys in each cluster // Returns inverse permutation of cluster indices, sorted from largest to // smallest. Adapted from diff --git a/freud/cluster/ClusterProperties.cc b/freud/cluster/ClusterProperties.cc index b748f0037..5a8d086e8 100644 --- a/freud/cluster/ClusterProperties.cc +++ b/freud/cluster/ClusterProperties.cc @@ -21,7 +21,7 @@ namespace freud { namespace cluster { getClusterInertiaMoments(). */ -void ClusterProperties::compute(const freud::locality::NeighborQuery* nq, const unsigned int* cluster_idx, +void ClusterProperties::compute(std::shared_ptr nq, const unsigned int* cluster_idx, const float* masses) { // determine the number of clusters @@ -30,12 +30,14 @@ void ClusterProperties::compute(const freud::locality::NeighborQuery* nq, const // allocate memory for the cluster properties and temporary arrays // initialize arrays to 0 - m_cluster_centers.prepare(num_clusters); - m_cluster_centers_of_mass.prepare(num_clusters); - m_cluster_moments_of_inertia.prepare({num_clusters, 3, 3}); - m_cluster_gyrations.prepare({num_clusters, 3, 3}); - m_cluster_sizes.prepare(num_clusters); - m_cluster_masses.prepare(num_clusters); + m_cluster_centers = std::make_shared>>(num_clusters); + m_cluster_centers_of_mass = std::make_shared>>(num_clusters); + m_cluster_moments_of_inertia + = std::make_shared>(std::vector {num_clusters, 3, 3}); + m_cluster_gyrations + = std::make_shared>(std::vector {num_clusters, 3, 3}); + m_cluster_sizes = std::make_shared>(num_clusters); + m_cluster_masses = std::make_shared>(num_clusters); // Create a vector to store cluster points, used to compute center of mass std::vector>> cluster_points(num_clusters, std::vector>()); @@ -48,25 +50,25 @@ void ClusterProperties::compute(const freud::locality::NeighborQuery* nq, const { const unsigned int c = cluster_idx[i]; cluster_points[c].push_back((*nq)[i]); - m_cluster_sizes[c]++; + (*m_cluster_sizes)[c]++; float mass = (masses != nullptr) ? masses[i] : float(1.0); - m_cluster_masses[c] += mass; + (*m_cluster_masses)[c] += mass; } // Now that we have located all of the cluster vectors, compute the centers const float* cluster_point_masses = masses; for (unsigned int c = 0; c < num_clusters; c++) { - m_cluster_centers[c] = nq->getBox().centerOfMass(cluster_points[c].data(), m_cluster_sizes[c]); - m_cluster_centers_of_mass[c] - = nq->getBox().centerOfMass(cluster_points[c].data(), m_cluster_sizes[c], cluster_point_masses); + (*m_cluster_centers)[c] = nq->getBox().centerOfMass(cluster_points[c].data(), (*m_cluster_sizes)[c]); + (*m_cluster_centers_of_mass)[c] = nq->getBox().centerOfMass( + cluster_points[c].data(), (*m_cluster_sizes)[c], cluster_point_masses); if (masses == nullptr) { cluster_point_masses = nullptr; } else { - cluster_point_masses = cluster_point_masses + m_cluster_sizes[c]; + cluster_point_masses = cluster_point_masses + (*m_cluster_sizes)[c]; } } @@ -77,48 +79,48 @@ void ClusterProperties::compute(const freud::locality::NeighborQuery* nq, const float mass = (masses != nullptr) ? masses[i] : float(1.0); unsigned int c = cluster_idx[i]; vec3 pos = (*nq)[i]; - vec3 mass_delta = nq->getBox().wrap(pos - m_cluster_centers_of_mass[c]); - vec3 delta = nq->getBox().wrap(pos - m_cluster_centers[c]); + vec3 mass_delta = nq->getBox().wrap(pos - (*m_cluster_centers_of_mass)[c]); + vec3 delta = nq->getBox().wrap(pos - (*m_cluster_centers)[c]); // get the start pointer for our 3x3 matrix - m_cluster_moments_of_inertia(c, 0, 0) + (*m_cluster_moments_of_inertia)(c, 0, 0) += (std::pow(mass_delta.y, 2) + std::pow(mass_delta.z, 2)) * mass; - m_cluster_moments_of_inertia(c, 0, 1) -= mass_delta.x * mass_delta.y * mass; - m_cluster_moments_of_inertia(c, 0, 2) -= mass_delta.x * mass_delta.z * mass; - m_cluster_moments_of_inertia(c, 1, 0) -= mass_delta.y * mass_delta.x * mass; - m_cluster_moments_of_inertia(c, 1, 1) + (*m_cluster_moments_of_inertia)(c, 0, 1) -= mass_delta.x * mass_delta.y * mass; + (*m_cluster_moments_of_inertia)(c, 0, 2) -= mass_delta.x * mass_delta.z * mass; + (*m_cluster_moments_of_inertia)(c, 1, 0) -= mass_delta.y * mass_delta.x * mass; + (*m_cluster_moments_of_inertia)(c, 1, 1) += (std::pow(mass_delta.x, 2) + std::pow(mass_delta.z, 2)) * mass; - m_cluster_moments_of_inertia(c, 1, 2) -= mass_delta.y * mass_delta.z * mass; - m_cluster_moments_of_inertia(c, 2, 0) -= mass_delta.z * mass_delta.x * mass; - m_cluster_moments_of_inertia(c, 2, 1) -= mass_delta.z * mass_delta.y * mass; - m_cluster_moments_of_inertia(c, 2, 2) + (*m_cluster_moments_of_inertia)(c, 1, 2) -= mass_delta.y * mass_delta.z * mass; + (*m_cluster_moments_of_inertia)(c, 2, 0) -= mass_delta.z * mass_delta.x * mass; + (*m_cluster_moments_of_inertia)(c, 2, 1) -= mass_delta.z * mass_delta.y * mass; + (*m_cluster_moments_of_inertia)(c, 2, 2) += (std::pow(mass_delta.x, 2) + std::pow(mass_delta.y, 2)) * mass; // get the start pointer for our 3x3 matrix - m_cluster_gyrations(c, 0, 0) += delta.x * delta.x; - m_cluster_gyrations(c, 0, 1) += delta.x * delta.y; - m_cluster_gyrations(c, 0, 2) += delta.x * delta.z; - m_cluster_gyrations(c, 1, 0) += delta.y * delta.x; - m_cluster_gyrations(c, 1, 1) += delta.y * delta.y; - m_cluster_gyrations(c, 1, 2) += delta.y * delta.z; - m_cluster_gyrations(c, 2, 0) += delta.z * delta.x; - m_cluster_gyrations(c, 2, 1) += delta.z * delta.y; - m_cluster_gyrations(c, 2, 2) += delta.z * delta.z; + (*m_cluster_gyrations)(c, 0, 0) += delta.x * delta.x; + (*m_cluster_gyrations)(c, 0, 1) += delta.x * delta.y; + (*m_cluster_gyrations)(c, 0, 2) += delta.x * delta.z; + (*m_cluster_gyrations)(c, 1, 0) += delta.y * delta.x; + (*m_cluster_gyrations)(c, 1, 1) += delta.y * delta.y; + (*m_cluster_gyrations)(c, 1, 2) += delta.y * delta.z; + (*m_cluster_gyrations)(c, 2, 0) += delta.z * delta.x; + (*m_cluster_gyrations)(c, 2, 1) += delta.z * delta.y; + (*m_cluster_gyrations)(c, 2, 2) += delta.z * delta.z; } // Normalize by the cluster sizes. for (unsigned int c = 0; c < num_clusters; c++) { - auto s = static_cast(m_cluster_sizes[c]); - m_cluster_gyrations(c, 0, 0) /= s; - m_cluster_gyrations(c, 0, 1) /= s; - m_cluster_gyrations(c, 0, 2) /= s; - m_cluster_gyrations(c, 1, 0) /= s; - m_cluster_gyrations(c, 1, 1) /= s; - m_cluster_gyrations(c, 1, 2) /= s; - m_cluster_gyrations(c, 2, 0) /= s; - m_cluster_gyrations(c, 2, 1) /= s; - m_cluster_gyrations(c, 2, 2) /= s; + auto s = static_cast((*m_cluster_sizes)[c]); + (*m_cluster_gyrations)(c, 0, 0) /= s; + (*m_cluster_gyrations)(c, 0, 1) /= s; + (*m_cluster_gyrations)(c, 0, 2) /= s; + (*m_cluster_gyrations)(c, 1, 0) /= s; + (*m_cluster_gyrations)(c, 1, 1) /= s; + (*m_cluster_gyrations)(c, 1, 2) /= s; + (*m_cluster_gyrations)(c, 2, 0) /= s; + (*m_cluster_gyrations)(c, 2, 1) /= s; + (*m_cluster_gyrations)(c, 2, 2) /= s; } } diff --git a/freud/cluster/ClusterProperties.h b/freud/cluster/ClusterProperties.h index 5a5322ec7..95ccabe5f 100644 --- a/freud/cluster/ClusterProperties.h +++ b/freud/cluster/ClusterProperties.h @@ -36,56 +36,60 @@ class ClusterProperties ClusterProperties() = default; //! Compute properties of the point clusters - void compute(const freud::locality::NeighborQuery* nq, const unsigned int* cluster_idx, + void compute(const std::shared_ptr nq, const unsigned int* cluster_idx, const float* masses = nullptr); //! Get a reference to the last computed cluster centers - const util::ManagedArray>& getClusterCenters() const + std::shared_ptr>> getClusterCenters() const { return m_cluster_centers; } //! Get a reference to the last computed cluster centers of mass - const util::ManagedArray>& getClusterCentersOfMass() const + std::shared_ptr>> getClusterCentersOfMass() const { return m_cluster_centers_of_mass; } //! Get a reference to the last computed cluster moments of inertia - const util::ManagedArray& getClusterMomentsOfInertia() const + std::shared_ptr> getClusterMomentsOfInertia() const { return m_cluster_moments_of_inertia; } //! Get a reference to the last computed cluster gyration tensors - const util::ManagedArray& getClusterGyrations() const + std::shared_ptr> getClusterGyrations() const { return m_cluster_gyrations; } //! Get a reference to the last computed cluster sizes - const util::ManagedArray& getClusterSizes() const + std::shared_ptr> getClusterSizes() const { return m_cluster_sizes; } //! Get a reference to the last computed cluster masses - const util::ManagedArray& getClusterMasses() const + std::shared_ptr> getClusterMasses() const { return m_cluster_masses; } private: - util::ManagedArray> m_cluster_centers; //!< Unweighted center of mass computed for each - //!< cluster (length: m_num_clusters) - util::ManagedArray> m_cluster_centers_of_mass; //!< Center of mass computed for each cluster - //!< (length: m_num_clusters) - util::ManagedArray m_cluster_moments_of_inertia; //!< Moment of inertia tensor computed for each - //!< cluster (m_num_clusters x 3 x 3 array) - util::ManagedArray m_cluster_gyrations; //!< Gyration tensor computed for each - //!< cluster (m_num_clusters x 3 x 3 array) - util::ManagedArray m_cluster_sizes; //!< Size per cluster - util::ManagedArray m_cluster_masses; //!< Mass per cluster + std::shared_ptr>> + m_cluster_centers; //!< Unweighted center of mass computed for each + //!< cluster (length: m_num_clusters) + std::shared_ptr>> + m_cluster_centers_of_mass; //!< Center of mass computed for each cluster + //!< (length: m_num_clusters) + std::shared_ptr> + m_cluster_moments_of_inertia; //!< Moment of inertia tensor computed for each + //!< cluster (m_num_clusters x 3 x 3 array) + std::shared_ptr> + m_cluster_gyrations; //!< Gyration tensor computed for each + //!< cluster (m_num_clusters x 3 x 3 array) + std::shared_ptr> m_cluster_sizes; //!< Size per cluster + std::shared_ptr> m_cluster_masses; //!< Mass per cluster }; }; }; // end namespace freud::cluster diff --git a/freud/cluster/export-Cluster.cc b/freud/cluster/export-Cluster.cc new file mode 100644 index 000000000..1cc233a54 --- /dev/null +++ b/freud/cluster/export-Cluster.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2010-2024 The Regents of the University of Michigan +// This file is from the freud project, released under the BSD 3-Clause License. + +#include +#include +#include +#include // NOLINT(misc-include-cleaner): used implicitly +#include + +#include + +#include "Cluster.h" + +namespace nb = nanobind; + +namespace freud { namespace cluster { +template +using nb_array = nanobind::ndarray; + +namespace wrap { +void compute(std::shared_ptr self, std::shared_ptr nq, + std::shared_ptr nlist, const locality::QueryArgs& qargs, + nb_array> keys) +{ + const auto* keys_data = reinterpret_cast(keys.data()); + self->compute(nq, nlist, qargs, keys_data); +} +}; // end namespace wrap + +namespace detail { +void export_Cluster(nb::module_& module) +{ + nanobind::class_(module, "Cluster") + .def(nb::init<>()) + .def("compute", &wrap::compute, nanobind::arg("nq"), nanobind::arg("nlist").none(), + nanobind::arg("qargs"), nanobind::arg("keys").none()) + .def("getNumClusters", &Cluster::getNumClusters) + .def("getClusterIdx", &Cluster::getClusterIdx) + .def("getClusterKeys", &Cluster::getClusterKeys); +}; + +}; // end namespace detail + +}; }; // namespace freud::cluster diff --git a/freud/cluster/export-ClusterProperties.cc b/freud/cluster/export-ClusterProperties.cc new file mode 100644 index 000000000..3aa15e4b5 --- /dev/null +++ b/freud/cluster/export-ClusterProperties.cc @@ -0,0 +1,48 @@ +// Copyright (c) 2010-2024 The Regents of the University of Michigan +// This file is from the freud project, released under the BSD 3-Clause License. + +#include +#include +#include +#include // NOLINT(misc-include-cleaner): used implicitly +#include + +#include + +#include "ClusterProperties.h" + +namespace nb = nanobind; + +namespace freud { namespace cluster { +template +using nb_array = nanobind::ndarray; + +namespace wrap { +void compute(std::shared_ptr self, std::shared_ptr nq, + nb_array> cluster_idx, + nb_array> masses) +{ + const auto* masses_data = reinterpret_cast(masses.data()); + const auto* cluster_idx_data = reinterpret_cast(cluster_idx.data()); + self->compute(nq, cluster_idx_data, masses_data); +} +}; // end namespace wrap + +namespace detail { +void export_ClusterProperties(nb::module_& module) +{ + nanobind::class_(module, "ClusterProperties") + .def(nb::init<>()) + .def("compute", &wrap::compute, nanobind::arg("nq"), nanobind::arg("cluster_idx"), + nanobind::arg("masses_data").none()) + .def("getClusterCenters", &ClusterProperties::getClusterCenters) + .def("getClusterCentersOfMass", &ClusterProperties::getClusterCentersOfMass) + .def("getClusterMomentsOfInertia", &ClusterProperties::getClusterMomentsOfInertia) + .def("getClusterGyrations", &ClusterProperties::getClusterGyrations) + .def("getClusterSizes", &ClusterProperties::getClusterSizes) + .def("getClusterMasses", &ClusterProperties::getClusterMasses); +}; + +}; // end namespace detail + +}; }; // namespace freud::cluster diff --git a/freud/cluster/module-Cluster.cc b/freud/cluster/module-Cluster.cc new file mode 100644 index 000000000..ef8c5339f --- /dev/null +++ b/freud/cluster/module-Cluster.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2010-2024 The Regents of the University of Michigan +// This file is from the freud project, released under the BSD 3-Clause License. + +#include +#include + +#include "NeighborQuery.h" + +namespace nb = nanobind; + +namespace freud::cluster::detail { +void export_Cluster(nb::module_& module); +void export_ClusterProperties(nb::module_& module); +} // namespace freud::cluster::detail + +using namespace freud::cluster::detail; + +NB_MODULE(_cluster, module) +{ + export_Cluster(module); + export_ClusterProperties(module); +}