Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ mark_as_advanced(
)

include(setupCPM)
include(setupPOET)

if(FINUFFT_USE_CPU)
add_subdirectory(src)
Expand Down
14 changes: 14 additions & 0 deletions cmake/setupPOET.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
CPMAddPackage(
NAME
POET
GIT_REPOSITORY
https://github.com/DiamonDinoia/poet.git
GIT_TAG
main
EXCLUDE_FROM_ALL
YES
GIT_SHALLOW
YES
OPTIONS
"POET_BUILD_TESTS OFF"
)
3 changes: 2 additions & 1 deletion include/cufinufft/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <utility> // for std::forward

#include <finufft_common/common.h>
#include <poet/poet.hpp>

#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
Expand Down Expand Up @@ -187,7 +188,7 @@ template<typename Func, typename T, typename... Args>
auto launch_dispatch_ns(Func &&func, int target_ns, Args &&...args) {
using NsSeq = make_range<MIN_NSPREAD, MAX_NSPREAD>;
auto params = std::make_tuple(DispatchParam<NsSeq>{target_ns});
return dispatch(std::forward<Func>(func), params, std::forward<Args>(args)...);
return poet::dispatch(std::forward<Func>(func), params, std::forward<Args>(args)...);
}

/**
Expand Down
115 changes: 0 additions & 115 deletions include/finufft_common/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,120 +33,5 @@ template<typename Seq> struct DispatchParam {
using seq_type = Seq;
};

// Cartesian product over integer sequences.
// Invokes f.template operator()<...>() for each combination of values.
// The functor F must provide a templated call operator.
// Adapted upon suggestion from Nils Wentzell: godbolt.org/z/GM94xb1j4
//
namespace detail {

template<typename F, typename... Seq> struct Product;

// Recursive case: at least two sequences remaining
template<typename F, int... I1, typename Seq2, typename... Rest>
struct Product<F, std::integer_sequence<int, I1...>, Seq2, Rest...> {
template<int... Prefix> static void apply(F &f) {
(Product<F, Seq2, Rest...>::template apply<Prefix..., I1>(f), ...);
}
};

// Base case: single sequence left
template<typename F, int... I1> struct Product<F, std::integer_sequence<int, I1...>> {
template<int... Prefix> static void apply(F &f) {
(f.template operator()<Prefix..., I1>(), ...);
}
};

template<typename F, typename... Seq> void product(F &f, Seq...) {
Product<F, Seq...>::template apply<>(f);
}

// Helper functor invoked for each combination to check runtime values
template<typename Func, std::size_t N, typename ArgTuple, typename ResultType>
struct DispatcherCaller {
Func &func;
const std::array<int, N> &vals;
ArgTuple &args;
std::conditional_t<std::is_void_v<ResultType>, char, ResultType> result{};
template<int... Params> void operator()() {
static constexpr std::array<int, sizeof...(Params)> p{Params...};
if (p == vals) {
if constexpr (std::is_void_v<ResultType>) {
std::apply(
[&](auto &&...a) {
func.template operator()<Params...>(std::forward<decltype(a)>(a)...);
},
args);
} else {
result = std::apply(
[&](auto &&...a) {
return func.template operator()<Params...>(std::forward<decltype(a)>(a)...);
},
args);
}
}
}
};

template<typename Seq> struct seq_first;
template<int I0, int... I>
struct seq_first<std::integer_sequence<int, I0, I...>> : std::integral_constant<int, I0> {
};

template<typename Tuple, std::size_t... I>
auto extract_vals_impl(const Tuple &t, std::index_sequence<I...>) {
return std::array<int, sizeof...(I)>{std::get<I>(t).runtime_val...};
}
template<typename Tuple> auto extract_vals(const Tuple &t) {
using T = std::remove_reference_t<Tuple>;
return extract_vals_impl(t, std::make_index_sequence<std::tuple_size_v<T>>{});
}

template<typename Tuple, std::size_t... I>
auto extract_seqs_impl(const Tuple &t, std::index_sequence<I...>) {
using T = std::remove_reference_t<Tuple>;
return std::make_tuple(typename std::tuple_element_t<I, T>::seq_type{}...);
}
template<typename Tuple> auto extract_seqs(const Tuple &t) {
using T = std::remove_reference_t<Tuple>;
return extract_seqs_impl(t, std::make_index_sequence<std::tuple_size_v<T>>{});
}

template<typename Func, typename ArgTuple, typename... Seq>
struct dispatch_result_helper {
template<std::size_t... I>
static auto test(std::index_sequence<I...>)
-> decltype(std::declval<Func>().template operator()<seq_first<Seq>::value...>(
std::get<I>(std::declval<ArgTuple>())...));
using type = decltype(test(std::make_index_sequence<std::tuple_size_v<ArgTuple>>{}));
};
template<typename Func, typename ArgTuple, typename SeqTuple> struct dispatch_result;
template<typename Func, typename ArgTuple, typename... Seq>
struct dispatch_result<Func, ArgTuple, std::tuple<Seq...>> {
using type = typename dispatch_result_helper<Func, ArgTuple, Seq...>::type;
};
template<typename Func, typename ArgTuple, typename SeqTuple>
using dispatch_result_t = typename dispatch_result<Func, ArgTuple, SeqTuple>::type;

} // namespace detail

// Generic dispatcher mapping runtime ints to template parameters.
// params is a tuple of DispatchParam holding runtime values and sequences.
// When a match is found, the functor is invoked with those template parameters
// and its result returned. Otherwise, the default-constructed result is returned.
template<typename Func, typename ParamTuple, typename... Args>
decltype(auto) dispatch(Func &&func, ParamTuple &&params, Args &&...args) {
using tuple_t = std::remove_reference_t<ParamTuple>;
constexpr std::size_t N = std::tuple_size_v<tuple_t>;
auto vals = detail::extract_vals(params);
auto seqs = detail::extract_seqs(params);
auto arg_tuple = std::forward_as_tuple(std::forward<Args>(args)...);
using result_t = detail::dispatch_result_t<Func, decltype(arg_tuple), decltype(seqs)>;
detail::DispatcherCaller<Func, N, decltype(arg_tuple), result_t> caller{func, vals,
arg_tuple};
std::apply([&](auto &&...s) { detail::product(caller, s...); }, seqs);
if constexpr (!std::is_void_v<result_t>) return caller.result;
}

} // namespace common
} // namespace finufft
67 changes: 46 additions & 21 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ XSIMD_URL := https://github.com/xtensor-stack/xsimd.git
XSIMD_VERSION := 14.0.0
XSIMD_DIR := $(DEPS_ROOT)/xsimd

# POET header-only dependency repo (fetched like xsimd)
POET_URL := https://github.com/DiamonDinoia/poet.git
POET_VERSION := main
POET_DIR := $(DEPS_ROOT)/poet

# DUCC sources optional dependency repo
DUCC_URL := https://github.com/mreineck/ducc.git
DUCC_VERSION := ducc0_0_39_1
Expand All @@ -92,7 +97,7 @@ FINUFFT = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
# Now come flags that should be added, whatever user overrode in make.inc.
# -fPIC (position-indep code) needed to build dyn lib (.so)
# Also, we force return (via :=) to the land of simply-expanded variables...
INCL = -Iinclude -I$(XSIMD_DIR)/include
INCL = -Iinclude -I$(XSIMD_DIR)/include -I$(POET_DIR)/include
# single-thread total list of math and FFT libs (now both precisions)...
# (Note: finufft tests use LIBSFFT; spread & util tests only need LIBS)
LIBSFFT := $(LIBS)
Expand Down Expand Up @@ -205,13 +210,13 @@ fortran/%.o: fortran/%.cpp $(HEADERS)
%.o: %.f
$(FC) -c $(FFLAGS) $< -o $@

# spreadinterp include auto-generated code, xsimd header-only dependency;
# spreadinterp include auto-generated code, xsimd and POET header-only dependencies;
# if FFT=DUCC also setup ducc with fft.h dependency on $(DUCC_SETUP)...
# Note src/spreadinterp.cpp includes finufft/finufft_core.h which includes finufft/fft.h
# so fftw/ducc header needed for spreadinterp, though spreadinterp should not
# depend on fftw/ducc directly?
include/finufft/fft.h: $(DUCC_SETUP)
SHEAD = $(wildcard src/*.h) $(XSIMD_DIR)/include/xsimd/xsimd.hpp
SHEAD = $(wildcard src/*.h) $(XSIMD_DIR)/include/xsimd/xsimd.hpp $(POET_DIR)/include/poet/poet.hpp
src/spreadinterp.o: $(SHEAD)

# we need xsimd functionality in finufft_core.h, which is included by many other
Expand Down Expand Up @@ -480,23 +485,31 @@ docker-wheel:
# ================== SETUP/COMPILE OF EXTERNAL DEPENDENCIES ===============

define clone_repo
@if [ ! -d "$(3)" ]; then \
echo "Cloning repository $(1) at tag $(2) into directory $(3)"; \
git clone --no-checkout $(1) $(3) && \
cd $(3) && \
git fetch origin tag $(2) --force && \
git -c advice.detachedHead=false checkout $(2); \
else \
cd $(3) && \
CURRENT_VERSION=$$(git describe --tags --abbrev=0 2>/dev/null || echo ""); \
if [ "$$CURRENT_VERSION" = "$(2)" ]; then \
echo "Directory $(3) already exists and is at the correct version $(2)."; \
else \
echo "Directory $(3) exists but is at version $$CURRENT_VERSION. Checking out the correct version $(2)."; \
git fetch origin tag $(2) --force && \
git -c advice.detachedHead=false checkout $(2) || { echo "Error: Failed to checkout version $(2) in $(3)."; exit 1; }; \
fi; \
fi
@if [ ! -d "$(3)" ]; then \
echo "Cloning repository $(1) at ref $(2) into directory $(3)"; \
git clone --no-checkout $(1) $(3) && \
cd $(3) && \
git fetch origin --prune >/dev/null 2>&1 || true; \
if git ls-remote --tags origin | grep -q "refs/tags/$(2)$$"; then \
git fetch origin tag $(2) --force && git -c advice.detachedHead=false checkout $(2) || { echo "Error: Failed to checkout tag $(2) in $(3)."; exit 1; }; \
elif git ls-remote --heads origin | grep -q "refs/heads/$(2)$$"; then \
git fetch origin $(2) --force && git -c advice.detachedHead=false checkout -B $(2) origin/$(2) || { echo "Error: Failed to checkout branch $(2) in $(3)."; exit 1; }; \
else \
git fetch origin --prune >/dev/null 2>&1 || true; \
git -c advice.detachedHead=false checkout $(2) || { echo "Error: Failed to checkout ref $(2) in $(3)."; exit 1; }; \
fi; \
else \
cd $(3) && \
git fetch origin --prune >/dev/null 2>&1 || true; \
if git ls-remote --tags origin | grep -q "refs/tags/$(2)$$"; then \
git fetch origin tag $(2) --force && git -c advice.detachedHead=false checkout $(2) && git reset --hard $(2) || { echo "Error: Failed to checkout tag $(2) in $(3)."; exit 1; }; \
elif git ls-remote --heads origin | grep -q "refs/heads/$(2)$$"; then \
git fetch origin $(2) --force && git -c advice.detachedHead=false checkout -B $(2) origin/$(2) && git reset --hard origin/$(2) || { echo "Error: Failed to checkout branch $(2) in $(3)."; exit 1; }; \
else \
git fetch origin --prune >/dev/null 2>&1 || true; \
git -c advice.detachedHead=false checkout $(2) || git checkout --force $(2) || { echo "Error: Failed to checkout ref $(2) in $(3)."; exit 1; }; \
fi; \
fi
endef


Expand All @@ -507,6 +520,18 @@ $(XSIMD_DIR)/include/xsimd/xsimd.hpp:
$(call clone_repo,$(XSIMD_URL),$(XSIMD_VERSION),$(XSIMD_DIR))
@echo "xsimd installed in deps/xsimd"

# download: POET header-only dependency (fetched like xsimd)
$(POET_DIR)/include/poet/poet.hpp:
mkdir -p $(DEPS_ROOT)
@echo "Checking POET external dependency..."
$(call clone_repo,$(POET_URL),$(POET_VERSION),$(POET_DIR))
@# ensure branch/tag/commit is present and init submodules
@git -C $(POET_DIR) fetch --prune >/dev/null 2>&1 || true
@echo "Attempting to checkout $(POET_VERSION) in $(POET_DIR)..."
@git -C $(POET_DIR) -c advice.detachedHead=false checkout $(POET_VERSION) >/dev/null 2>&1 || true
@git -C $(POET_DIR) submodule update --init --recursive >/dev/null 2>&1 || true
@echo "POET installed in deps/poet"

# download DUCC... (an empty target just used to track if installed)
$(DUCC_COOKIE):
mkdir -p $(DEPS_ROOT)
Expand All @@ -521,7 +546,7 @@ $(DUCC_SRCS): %.cc: $(DUCC_SETUP)
$(DUCC_OBJS): %.o: %.cc
$(CXX) -c $(DUCC_CXXFLAGS) $(DUCC_INCL) $< -o $@

setup: $(XSIMD_DIR)/include/xsimd/xsimd.hpp $(DUCC_SETUP)
setup: $(XSIMD_DIR)/include/xsimd/xsimd.hpp $(POET_DIR)/include/poet/poet.hpp $(DUCC_SETUP)

setupclean:
rm -rf $(DEPS_ROOT)
Expand Down
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ if(FINUFFT_USE_DUCC0)
target_compile_definitions(finufft PRIVATE FINUFFT_USE_DUCC0)
endif()

target_link_libraries(finufft PRIVATE $<BUILD_INTERFACE:finufft_fftlibs xsimd finufft_common>)
target_link_libraries(finufft PRIVATE $<BUILD_INTERFACE:finufft_fftlibs xsimd finufft_common poet::poet>)
if(FINUFFT_USE_OPENMP)
target_link_libraries(finufft PRIVATE OpenMP::OpenMP_CXX)
if(NOT FINUFFT_STATIC_LINKING)
Expand Down
3 changes: 2 additions & 1 deletion src/cuda/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ if(FINUFFT_SHARED_LINKING)
endif()
endif()

target_link_libraries(cufinufft PRIVATE CUDA::cudart CUDA::cufft $<BUILD_INTERFACE:finufft_common>)
target_link_libraries(cufinufft PRIVATE CUDA::cudart CUDA::cufft)
target_link_libraries(cufinufft PUBLIC $<BUILD_INTERFACE:finufft_common> poet::poet)
# Expose only when not doing fully static linking
if(NOT FINUFFT_STATIC_LINKING)
target_link_libraries(cufinufft PUBLIC CUDA::cudart CUDA::cufft)
Expand Down
11 changes: 6 additions & 5 deletions src/spreadinterp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <finufft/finufft_utils.hpp>
#include <finufft/spreadinterp.h>
#include <finufft_common/kernel.h>
#include <poet/poet.hpp>

#include <finufft/xsimd.hpp>

Expand All @@ -15,7 +16,7 @@

using namespace std;
using namespace finufft::utils; // access to timer
using namespace finufft::common; // access to constants and dispatch
using namespace finufft::common; // access to constants
using namespace finufft::kernel; // access to kernel evaluation funcs

namespace finufft::spreadinterp {
Expand Down Expand Up @@ -911,7 +912,7 @@
using NcSeq = make_range<MIN_NC, MAX_NC>;
auto params =
std::make_tuple(DispatchParam<NsSeq>{opts.nspread}, DispatchParam<NcSeq>{nc});
dispatch(caller, params);
poet::dispatch(caller, params);
}

template<typename T, int ns, int nc>
Expand Down Expand Up @@ -1053,7 +1054,7 @@
using NcSeq = make_range<MIN_NC, MAX_NC>;
auto params =
std::make_tuple(DispatchParam<NsSeq>{opts.nspread}, DispatchParam<NcSeq>{nc});
dispatch(caller, params);
poet::dispatch(caller, params);
}

template<typename T, int ns, int nc>
Expand Down Expand Up @@ -1179,7 +1180,7 @@
using NcSeq = make_range<MIN_NC, MAX_NC>;
auto params =
std::make_tuple(DispatchParam<NsSeq>{opts.nspread}, DispatchParam<NcSeq>{nc});
dispatch(caller, params);
poet::dispatch(caller, params);
}

template<typename T, bool thread_safe>
Expand Down Expand Up @@ -1717,7 +1718,7 @@
nb);
} // end of choice of which t1 spread type to use
return 0;
};

Check warning on line 1721 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-10)

extra ‘;’ [-Wpedantic]

// --------------------------------------------------------------------------
template<typename T, int ns, int nc>
Expand Down Expand Up @@ -1870,7 +1871,7 @@
using NcSeq = make_range<MIN_NC, MAX_NC>;
auto params =
std::make_tuple(DispatchParam<NsSeq>{opts.nspread}, DispatchParam<NcSeq>{nc});
return dispatch(caller, params);
return poet::dispatch(caller, params);
}

template<typename T>
Expand Down Expand Up @@ -2015,7 +2016,7 @@

template<typename T>
int setup_spreader(finufft_spread_opts &opts, T eps, double upsampfac, int kerevalmeth,
int debug, int showwarn, int spreadinterponly, int dim, int kerformula)

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / valgrind

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / valgrind

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (macos-15, gcc-15)

unused parameter 'debug' [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (macos-15, gcc-15)

unused parameter 'debug' [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (macos-15, gcc-15)

unused parameter 'debug' [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (macos-15, gcc-15)

unused parameter 'debug' [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (macos-14, gcc-14)

unused parameter 'debug' [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (macos-14, gcc-14)

unused parameter 'debug' [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (macos-14, gcc-14)

unused parameter 'debug' [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (macos-14, gcc-14)

unused parameter 'debug' [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-12)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-12)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-12)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-12)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-12)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-12)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-11)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-11)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-11)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-11)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-11)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-11)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-13)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-13)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-13)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-13)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-13)

unused parameter ‘debug’ [-Wunused-parameter]

Check warning on line 2019 in src/spreadinterp.cpp

View workflow job for this annotation

GitHub Actions / cmake-ci (ubuntu-22.04, gcc-13)

unused parameter ‘debug’ [-Wunused-parameter]
/* Initializes spreader kernel parameters given desired NUFFT tolerance eps,
upsampling factor (=sigma in paper, or R in Dutt-Rokhlin), and debug flags.
Horner polynomial evaluation is always used; the kerevalmeth argument is
Expand Down
Loading