Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert Box Module to Use nanobind #1256

Merged
merged 26 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
161eada
write skeleton cmake code for building with pybind11
tommy-waltmann May 21, 2024
a9c5eed
keep working on skeleton code
tommy-waltmann May 28, 2024
622742b
start working on functions that pass array dat
tommy-waltmann Jun 3, 2024
b79e7c2
changes so tests pass with pybind11
tommy-waltmann Jun 3, 2024
88eed2c
remove files we don't need anymore
tommy-waltmann Jun 3, 2024
d8dda25
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 3, 2024
a9134cb
changes for nanobind
tommy-waltmann Jun 5, 2024
3888b3f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 5, 2024
ee033d3
Update cpp/box/Box.h
tommy-waltmann Jun 6, 2024
a55c56c
Update CMakeLists.txt
tommy-waltmann Jun 11, 2024
5fa295c
streamline cmake code in python directory
tommy-waltmann Jun 11, 2024
fd6729e
change cmake version requirements
tommy-waltmann Jun 11, 2024
024b5f4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 11, 2024
73a05b9
remove unnecessary passing of array sizes and clarify function structure
tommy-waltmann Jun 11, 2024
72f42d2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 11, 2024
825ba64
remove redundant stuff from python
tommy-waltmann Jun 12, 2024
91e32ef
move all binding code to its own header
tommy-waltmann Jun 12, 2024
e3e8c06
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 12, 2024
d001381
add namespace and shared pointers
tommy-waltmann Jun 13, 2024
7af2ccd
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 13, 2024
e5848c2
Update CMakeLists.txt
tommy-waltmann Jun 14, 2024
111ca13
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 14, 2024
2939bf7
move wrapper code to its own translation unit
tommy-waltmann Jun 14, 2024
df19cf9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 14, 2024
a66be9f
merge branch pybind11 into pybind11-box
tommy-waltmann Jun 19, 2024
33326d1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions CMakeLists.txt
tommy-waltmann marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# CMake 3.12.0 is the oldest version supported by the way freud links TBB to
# object libraries like _cluster. This is also the oldest version tested in CI.
cmake_minimum_required(VERSION 3.12.0)
cmake_minimum_required(VERSION 3.15...3.30)

project(freud)

Expand All @@ -27,6 +25,19 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
# https://stackoverflow.com/questions/50600708/combining-cmake-object-libraries-with-shared-libraries
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_subdirectory(CMake)

# find python
if(CMAKE_VERSION VERSION_LESS 3.18)
set(DEV_MODULE Development)
else()
set(DEV_MODULE Development.Module)
endif()

find_package(
Python 3.8
COMPONENTS Interpreter ${DEV_MODULE}
REQUIRED)

find_package_config_first(TBB)

if(TBB_FOUND)
Expand All @@ -36,6 +47,18 @@ if(TBB_FOUND)
"[${TBB_LIBRARY}][${TBB_INCLUDE_DIR}]")
endif()

# go find nanobind
execute_process(
COMMAND ${Python_EXECUTABLE} "-m" "nanobind" "--cmake_dir"
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE nanobind_ROOT)
find_package(nanobind CONFIG REQUIRED)
if(nanobind_FOUND)
find_package_message(
nanobind "Found nanobind: ${nanobind_DIR} ${nanobind_VERSION}"
"[${nanobind_DIR},${nanobind_VERSION}]")
endif()

# Fail fast if users have not cloned submodules.
tommy-waltmann marked this conversation as resolved.
Show resolved Hide resolved
if(NOT WIN32)
string(ASCII 27 Esc)
Expand Down Expand Up @@ -76,7 +99,3 @@ set(ignoreMe "${SKBUILD}")

add_subdirectory(cpp)
add_subdirectory(freud)

if(_using_conda OR DEFINED ENV{CIBUILDWHEEL})
set_target_properties(libfreud PROPERTIES INSTALL_RPATH_USE_LINK_PATH True)
endif()
34 changes: 25 additions & 9 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,31 @@ if(WIN32)
add_compile_options(/DNOMINMAX)
endif()

add_subdirectory(cluster)
add_subdirectory(density)
add_subdirectory(diffraction)
add_subdirectory(environment)
add_subdirectory(locality)
add_subdirectory(order)
add_subdirectory(parallel)
add_subdirectory(pmft)
add_subdirectory(util)
# Detect when building against a conda environment set the _using_conda variable
# for use both in this file and in the parent
get_filename_component(_python_bin_dir ${PYTHON_EXECUTABLE} DIRECTORY)
if(EXISTS "${_python_bin_dir}/../conda-meta")
message("-- Detected conda environment, setting INSTALL_RPATH_USE_LINK_PATH")
set(_using_conda On)
set(_using_conda
On
PARENT_SCOPE)
else()
set(_using_conda Off)
set(_using_conda
Off
PARENT_SCOPE)
endif()
tommy-waltmann marked this conversation as resolved.
Show resolved Hide resolved

add_subdirectory(box)

# commented out for now, uncomment them as the conversion to pybind11 progresses
# add_subdirectory(cluster) add_subdirectory(density)
# add_subdirectory(diffraction) add_subdirectory(environment)
# add_subdirectory(locality) add_subdirectory(order) add_subdirectory(parallel)
# add_subdirectory(pmft) add_subdirectory(util)
tommy-waltmann marked this conversation as resolved.
Show resolved Hide resolved

#[[
add_library(
libfreud SHARED
$<TARGET_OBJECTS:_cluster>
Expand Down Expand Up @@ -53,3 +68,4 @@ if(CMAKE_EXPORT_COMPILE_COMMANDS)
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/compile_commands.json
${PROJECT_SOURCE_DIR})
endif()
]]
tommy-waltmann marked this conversation as resolved.
Show resolved Hide resolved
38 changes: 11 additions & 27 deletions cpp/box/Box.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
#ifndef BOX_H
#define BOX_H

#include "utils.h"
#include <algorithm>
#include <complex>
#include <sstream>
#include <stdexcept>

#include "VectorMath.h"
#include "utils.h"

/*! \file Box.h
\brief Represents simulation boxes and contains helpful wrapping functions.
Expand Down Expand Up @@ -93,12 +93,6 @@ class Box
return !(*this == b);
}

//! Set L, box lengths, inverses. Box is also centered at zero.
void setL(const vec3<float>& L)
{
setL(L.x, L.y, L.z);
}

DomFijan marked this conversation as resolved.
Show resolved Hide resolved
//! Set L, box lengths, inverses. Box is also centered at zero.
void setL(const float Lx, const float Ly, const float Lz)
{
Expand Down Expand Up @@ -156,9 +150,9 @@ class Box
}

//! Get current stored inverse of L
vec3<float> getLinv() const
std::vector<float> getLinv() const
{
return m_Linv;
return {m_Linv.x, m_Linv.y, m_Linv.z};
}

//! Get tilt factor xy
Expand Down Expand Up @@ -227,10 +221,9 @@ class Box
//! Convert fractional coordinates into absolute coordinates in place
/*! \param vecs Vectors of fractional coordinates between 0 and 1 within
* parallelepipedal box
* \param Nvecs Number of vectors
* \param out The array in which to place the wrapped vectors.
* \param out_data The array in which to place the wrapped vectors.
*/
void makeAbsolute(const vec3<float>* vecs, unsigned int Nvecs, vec3<float>* out) const
void makeAbsolute(const vec3<float>* vecs, const unsigned int Nvecs, vec3<float>* out) const
{
util::forLoopWrapper(0, Nvecs, [&](size_t begin, size_t end) {
for (size_t i = begin; i < end; ++i)
Expand Down Expand Up @@ -294,12 +287,12 @@ class Box
* \param Nvecs Number of vectors
\param res Array to save the images
*/
void getImages(vec3<float>* vecs, unsigned int Nvecs, vec3<int>* res) const
void getImages(const vec3<float>* vecs, unsigned int Nvecs, vec3<int>* images) const
{
util::forLoopWrapper(0, Nvecs, [&](size_t begin, size_t end) {
for (size_t i = begin; i < end; ++i)
{
getImage(vecs[i], res[i]);
getImage(vecs[i], images[i]);
}
});
}
Expand Down Expand Up @@ -374,7 +367,7 @@ class Box
* \param masses Optional array of masses, of length Nvecs
* \return Center of mass as a vec3<float>
*/
vec3<float> centerOfMass(vec3<float>* vecs, size_t Nvecs, const float* masses = nullptr) const
vec3<float> centerOfMass(vec3<float>* vecs, size_t Nvecs, const float* masses) const
{
// This roughly follows the implementation in
// https://en.wikipedia.org/wiki/Center_of_mass#Systems_with_periodic_boundary_conditions
Expand All @@ -386,7 +379,7 @@ class Box
vec3<float> phase(constants::TWO_PI * makeFractional(vecs[i]));
vec3<std::complex<float>> xi(std::polar(float(1.0), phase.x), std::polar(float(1.0), phase.y),
std::polar(float(1.0), phase.z));
float mass = (masses != nullptr) ? masses[i] : float(1.0);
float mass = masses[i];
total_mass += mass;
xi_mean += std::complex<float>(mass, 0) * xi;
}
Expand All @@ -401,7 +394,7 @@ class Box
* \param Nvecs Number of vectors
* \param masses Optional array of masses, of length Nvecs
*/
void center(vec3<float>* vecs, unsigned int Nvecs, const float* masses = nullptr) const
void center(vec3<float>* vecs, unsigned int Nvecs, const float* masses) const
{
vec3<float> com(centerOfMass(vecs, Nvecs, masses));
util::forLoopWrapper(0, Nvecs, [&](size_t begin, size_t end) {
Expand Down Expand Up @@ -433,10 +426,6 @@ class Box
void computeDistances(const vec3<float>* query_points, const unsigned int n_query_points,
const vec3<float>* points, const unsigned int n_points, float* distances) const
{
if (n_query_points != n_points)
{
throw std::invalid_argument("The number of query points and points must match.");
}
util::forLoopWrapper(0, n_query_points, [&](size_t begin, size_t end) {
for (size_t i = begin; i < end; ++i)
{
Expand Down Expand Up @@ -473,7 +462,7 @@ class Box
\param n_points The number of points.
\param contains_mask Mask of points inside the box.
*/
void contains(const vec3<float>* points, const unsigned int n_points, bool* contains_mask) const
void contains(vec3<float>* points, const unsigned int n_points, bool* contains_mask) const
{
util::forLoopWrapper(0, n_points, [&](size_t begin, size_t end) {
std::transform(&points[begin], &points[end], &contains_mask[begin],
Expand Down Expand Up @@ -528,11 +517,6 @@ class Box
/*! \param periodic Flags to set
* \post Period flags are set to \a periodic
*/
void setPeriodic(vec3<bool> periodic)
{
m_periodic = periodic;
}

void setPeriodic(bool x, bool y, bool z)
{
m_periodic = vec3<bool>(x, y, z);
Expand Down
22 changes: 22 additions & 0 deletions cpp/box/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# create the target and add the needed properties
nanobind_add_module(_box SHARED module-box.cc export_Box.cc)
target_link_libraries(_box PUBLIC TBB::tbb)
# this probably isn't needed for box, but may be needed by other modules
# target_compile_definitions( box # Avoid deprecation warnings for unsupported
# NumPy API versions. See #
# https://numpy.org/doc/1.19/reference/c-api/deprecations.html PRIVATE
# "NPY_NO_DEPRECATED_API=NPY_1_10_API_VERSION" # Default voro++ verbosity is
# high. PRIVATE "VOROPP_VERBOSE=1")

if(APPLE)
set_target_properties(_box PROPERTIES INSTALL_RPATH "@loader_path")
else()
set_target_properties(_box PROPERTIES INSTALL_RPATH "\$ORIGIN")
endif()

if(_using_conda OR DEFINED ENV{CIBUILDWHEEL})
set_target_properties(_box PROPERTIES INSTALL_RPATH_USE_LINK_PATH True)
endif()
tommy-waltmann marked this conversation as resolved.
Show resolved Hide resolved

# install
install(TARGETS _box DESTINATION freud)
107 changes: 107 additions & 0 deletions cpp/box/export_Box.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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 "export_Box.h"

namespace nb = nanobind;

namespace freud { namespace box { namespace wrap {

void makeAbsolute(std::shared_ptr<Box> box, nb_array<float, nb::shape<-1, 3>> vecs,
nb_array<float, nb::shape<-1, 3>> out)
{
unsigned int Nvecs = vecs.shape(0);
vec3<float>* vecs_data = (vec3<float>*) (vecs.data());
vec3<float>* out_data = (vec3<float>*) (out.data());
box->makeAbsolute(vecs_data, Nvecs, out_data);
}

void makeFractional(std::shared_ptr<Box> box, nb_array<float, nb::shape<-1, 3>> vecs,
nb_array<float, nb::shape<-1, 3>> out)
{
unsigned int Nvecs = vecs.shape(0);
vec3<float>* vecs_data = (vec3<float>*) (vecs.data());
vec3<float>* out_data = (vec3<float>*) (out.data());
box->makeFractional(vecs_data, Nvecs, out_data);
}

void getImages(std::shared_ptr<Box> box, nb_array<float, nb::shape<-1, 3>> vecs,
nb_array<int, nb::shape<-1, 3>> images)
{
const unsigned int Nvecs = vecs.shape(0);
vec3<float>* vecs_data = (vec3<float>*) (vecs.data());
vec3<int>* images_data = (vec3<int>*) (images.data());
box->getImages(vecs_data, Nvecs, images_data);
}

void wrap(std::shared_ptr<Box> box, nb_array<float, nb::shape<-1, 3>> vecs,
nb_array<float, nb::shape<-1, 3>> out)
{
const unsigned int Nvecs = vecs.shape(0);
vec3<float>* vecs_data = (vec3<float>*) (vecs.data());
vec3<float>* out_data = (vec3<float>*) (out.data());
box->wrap(vecs_data, Nvecs, out_data);
}

void unwrap(std::shared_ptr<Box> box, nb_array<float> vecs, nb_array<int> images, nb_array<float> out)
{
const unsigned int Nvecs = vecs.shape(0);
vec3<float>* vecs_data = (vec3<float>*) (vecs.data());
vec3<int>* images_data = (vec3<int>*) (images.data());
vec3<float>* out_data = (vec3<float>*) (out.data());
box->unwrap(vecs_data, images_data, Nvecs, out_data);
}

std::vector<float> centerOfMass(std::shared_ptr<Box> box, nb_array<float> vecs,
nb_array<float, nb::shape<-1>> masses)
{
const unsigned int Nvecs = vecs.shape(0);
vec3<float>* vecs_data = (vec3<float>*) (vecs.data());
float* masses_data = (float*) (masses.data());
auto com = box->centerOfMass(vecs_data, Nvecs, masses_data);
return {com.x, com.y, com.z};
}

void center(std::shared_ptr<Box> box, nb_array<float> vecs, nb_array<float, nb::ndim<1>> masses)
{
const unsigned int Nvecs = vecs.shape(0);
vec3<float>* vecs_data = (vec3<float>*) (vecs.data());
float* masses_data = (float*) (masses.data());
box->center(vecs_data, Nvecs, masses_data);
}

void computeDistances(std::shared_ptr<Box> box, nb_array<float> query_points, nb_array<float> points,
nb_array<float, nb::ndim<1>> distances)
{
const unsigned int n_query_points = query_points.shape(0);
vec3<float>* query_points_data = (vec3<float>*) (query_points.data());
const unsigned int n_points = points.shape(0);
vec3<float>* points_data = (vec3<float>*) (points.data());
float* distances_data = (float*) (distances.data());
if (n_query_points != n_points)
{
throw std::invalid_argument("The number of query points and points must match.");
}
box->computeDistances(query_points_data, n_query_points, points_data, n_points, distances_data);
}

void computeAllDistances(std::shared_ptr<Box> box, nb_array<float> query_points, nb_array<float> points,
nb_array<float, nb::ndim<2>> distances)
{
const unsigned int n_query_points = query_points.shape(0);
vec3<float>* query_points_data = (vec3<float>*) (query_points.data());
const unsigned int n_points = points.shape(0);
vec3<float>* points_data = (vec3<float>*) (points.data());
float* distances_data = (float*) (distances.data());
box->computeAllDistances(query_points_data, n_query_points, points_data, n_points, distances_data);
}

void contains(std::shared_ptr<Box> box, nb_array<float> points, nb_array<bool, nb::ndim<1>> contains_mask)
{
const unsigned int n_points = points.shape(0);
vec3<float>* points_data = (vec3<float>*) (points.data());
bool* contains_mask_data = (bool*) (contains_mask.data());
box->contains(points_data, n_points, contains_mask_data);
}

}; }; }; // namespace freud::box::wrap
Loading
Loading