This commit is contained in:
Timur A. Fatkhullin
2025-05-07 00:01:14 +03:00
parent 01485ed2e1
commit cfe1fc8fab
4 changed files with 209 additions and 128 deletions

View File

@@ -20,11 +20,12 @@ enable_language(Fortran CXX)
include(FortranCInterface)
FortranCInterface_HEADER(FortranCInterface.h
MACRO_NAMESPACE "FC_"
SYMBOL_NAMESPACE "fp_"
SYMBOLS ${func_str}
# SYMBOL_NAMESPACE "fp_"
SYMBOL_NAMESPACE ""
# SYMBOLS ${func_str}
SYMBOLS ${func_name}
)
FortranCInterface_VERIFY(CXX)
add_library(fitpack STATIC ${src_files} fitpack.h)
set(FITPACK_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR})

View File

@@ -1,38 +1,13 @@
#pragma once
#include <expected>
#include <limits>
#include <memory>
#include <ranges>
#include <vector>
namespace mcc::fitpack
{
#include "/home/timur/PROGRAMS/C++/build-mountcontrol-Desktop-Debug/cxx/fitpack/FortranCInterface.h"
extern "C" {
void curfit(int* iopt,
int* m,
double* x,
double* y,
double* w,
double* xb,
double* xe,
int* k,
double* s,
int* nest,
int* n,
double* t,
double* c,
double* fp,
double* wrk,
int* lwrk,
int* iwrk,
int* ier);
void splev(double* t, int* n, double* c, int* k, double* x, double* y, int* m, int* e, int* ier);
void splder(double* t, int* n, double* c, int* k, int* nu, double* x, double* y, int* m, int* e, double* wrk, int* ier);
void surfit(int* iopt,
int* m,
double* x,
@@ -130,7 +105,11 @@ void sphere(int* iopt,
template <std::ranges::contiguous_range TethaT,
namespace mcc::fitpack
{
template <int IOPT = 0,
std::ranges::contiguous_range TethaT,
std::ranges::contiguous_range PhiT,
std::ranges::contiguous_range FuncT,
typename WeightT,
@@ -156,7 +135,8 @@ int fitpack_sphere_smooth(const TethaT& tetha,
std::same_as<std::ranges::range_value_t<PhiT>, double> &&
std::same_as<std::ranges::range_value_t<FuncT>, double> &&
std::same_as<std::ranges::range_value_t<TKnotT>, double> &&
std::same_as<std::ranges::range_value_t<PKnotT>, double>,
std::same_as<std::ranges::range_value_t<PKnotT>, double> &&
std::same_as<std::ranges::range_value_t<CoeffT>, double>,
"Input ranges elements type must be double!");
if constexpr (std::ranges::contiguous_range<WeightT>) {
@@ -164,7 +144,11 @@ int fitpack_sphere_smooth(const TethaT& tetha,
"Input ranges elements type must be double!");
}
auto m = std::min(std::min(std::ranges::size(tetha), std::ranges::size(phi)), std::ranges::size(func));
static_assert(IOPT != -1 || IOPT != 0 || IOPT != 1, "Invalid IOPT template parameter value!");
int m = std::min(std::min(std::ranges::size(tetha), std::ranges::size(phi)), std::ranges::size(func));
if (m < 2) {
return 10;
}
@@ -210,33 +194,47 @@ int fitpack_sphere_smooth(const TethaT& tetha,
const int uv = u * v;
const int v2 = v * v;
const int lwrk1 = 185 + 52 * v + 10 * u + 14 * uv + 8 * (u - 1) * v2 + 8 * m;
const int lwrk2 = 48 + 21 * v + 7 * uv + 4 * (u - 1) * v2;
const int kwrk = m + uv;
int lwrk1 = 185 + 52 * v + 10 * u + 14 * uv + 8 * (u - 1) * v2 + 8 * m;
int lwrk2 = 48 + 21 * v + 7 * uv + 4 * (u - 1) * v2;
int kwrk = m + uv;
std::unique_ptr<double> wrk1{new double(lwrk1)};
std::unique_ptr<double> wrk2{new double(lwrk2)};
std::unique_ptr<int> iwrk{new int(kwrk)};
std::vector<double> wrk1(lwrk1);
std::vector<double> wrk2(lwrk2);
std::vector<int> iwrk(kwrk);
const int n_coeffs = (ntest - 4) * (npest - 4);
if (std::ranges::size(coeffs) < n_coeffs) { // resize
std::ranges::fill_n(std::back_inserter(coeffs), n_coeffs - std::ranges::size(coeffs), 0.0);
}
const int iopt = 0;
int iopt = IOPT;
auto tetha_ptr = const_cast<double*>(std::ranges::data(tetha));
auto phi_ptr = const_cast<double*>(std::ranges::data(phi));
auto func_ptr = const_cast<double*>(std::ranges::data(func));
auto tetha_knots_ptr = const_cast<double*>(std::ranges::data(tetha_knots));
auto phi_knots_ptr = const_cast<double*>(std::ranges::data(phi_knots));
if constexpr (std::ranges::contiguous_range<WeightT>) {
res = sphere(&iopt, &m, std::ranges::data(tetha), std::ranges::data(phi), std::ranges::data(func),
std::ranges::data(weight), &s_par, &ntest, &npest, &eps, &ntest, std::ranges::data(tetha_knots),
&npest, std::ranges::data(phi_knots), std::ranges::data(coeffs), &resi2_sum, wrk1.get(), &lwrk1,
wrk2.get(), &lwrk2, iwrk.get(), &kwrk, &res);
auto weight_ptr = const_cast<double*>(std::ranges::data(weight));
sphere(&iopt, &m, tetha_ptr, phi_ptr, func_ptr, weight_ptr, &s_par, &ntest, &npest, &eps, &ntest,
tetha_knots_ptr, &npest, phi_knots_ptr, std::ranges::data(coeffs), &resi2_sum, wrk1.data(), &lwrk1,
wrk2.data(), &lwrk2, iwrk.data(), &kwrk, &res);
// sphere(&iopt, &m, std::ranges::data(tetha), std::ranges::data(phi), std::ranges::data(func),
// std::ranges::data(weight), &s_par, &ntest, &npest, &eps, &ntest, std::ranges::data(tetha_knots),
// &npest, std::ranges::data(phi_knots), std::ranges::data(coeffs), &resi2_sum, wrk1.data(), &lwrk1,
// wrk2.data(), &lwrk2, iwrk.data(), &kwrk, &res);
} else {
std::vector<double> weight_vec(m, weight);
res = sphere(&iopt, &m, std::ranges::data(tetha), std::ranges::data(phi), std::ranges::data(func),
weight_vec.data(), &s_par, &ntest, &npest, &eps, &ntest, std::ranges::data(tetha_knots), &npest,
std::ranges::data(phi_knots), std::ranges::data(coeffs), &resi2_sum, wrk1.get(), &lwrk1,
wrk2.get(), &lwrk2, iwrk.get(), &kwrk, &res);
sphere(&iopt, &m, tetha_ptr, phi_ptr, func_ptr, weight_vec.data(), &s_par, &ntest, &npest, &eps, &ntest,
tetha_knots_ptr, &npest, phi_knots_ptr, std::ranges::data(coeffs), &resi2_sum, wrk1.data(), &lwrk1,
wrk2.data(), &lwrk2, iwrk.data(), &kwrk, &res);
// res = sphere(&iopt, &m, std::ranges::data(tetha), std::ranges::data(phi), std::ranges::data(func),
// weight_vec.data(), &s_par, &ntest, &npest, &eps, &ntest, std::ranges::data(tetha_knots), &npest,
// std::ranges::data(phi_knots), std::ranges::data(coeffs), &resi2_sum, wrk1.get(), &lwrk1,
// wrk2.get(), &lwrk2, iwrk.get(), &kwrk, &res);
}
@@ -257,8 +255,8 @@ int fitpack_sphere_fit(const TethaT& tetha,
const PhiT& phi,
const FuncT& func,
const WeightT& weight,
const TKnotT& tetha_knots,
const PKnotT& phi_knots,
TKnotT& tetha_knots,
PKnotT& phi_knots,
CoeffT& coeffs,
double& resi2_sum,
double eps = std::numeric_limits<double>::epsilon())
@@ -267,104 +265,73 @@ int fitpack_sphere_fit(const TethaT& tetha,
int nt = std::ranges::size(tetha_knots);
int np = std::ranges::size(phi_knots);
return fitpack_sphere_smooth(tetha, phi, func, weight, s, nt, np, tetha_knots, phi_knots, coeffs, resi2_sum, eps);
return fitpack_sphere_smooth<-1>(tetha, phi, func, weight, s, nt, np, tetha_knots, phi_knots, coeffs, resi2_sum,
eps);
}
/*
template <std::ranges::contiguous_range TethaT,
std::ranges::contiguous_range PhiT,
std::ranges::contiguous_range FuncT,
typename WeightT,
std::ranges::contiguous_range TKnotT,
std::ranges::contiguous_range PKnotT,
std::ranges::contiguous_range CoeffT>
int fitpack_sphere_fit(const TethaT& tetha,
const PhiT& phi,
const FuncT& func,
const WeightT& weight,
const TKnotT& tetha_knots,
const PKnotT& phi_knots,
CoeffT& coeffs,
double& resi2_sum,
double eps = std::numeric_limits<double>::epsilon())
requires((std::ranges::contiguous_range<WeightT> || std::convertible_to<WeightT, double>) &&
std::ranges::output_range<CoeffT, double>)
template <std::ranges::contiguous_range TXT,
std::ranges::contiguous_range TYT,
std::ranges::contiguous_range XT,
std::ranges::contiguous_range YT,
std::ranges::contiguous_range CoeffT,
std::ranges::contiguous_range FuncT>
int fitpack_eval_spl2d(const TXT& tx,
const TYT& ty,
const CoeffT& coeffs,
const XT& x,
const YT& y,
FuncT& func,
int kx = 3,
int ky = 3)
{
static_assert(std::same_as<std::ranges::range_value_t<TethaT>, double> &&
std::same_as<std::ranges::range_value_t<PhiT>, double> &&
std::same_as<std::ranges::range_value_t<FuncT>, double> &&
std::same_as<std::ranges::range_value_t<TKnotT>, double> &&
std::same_as<std::ranges::range_value_t<PKnotT>, double>,
static_assert(std::same_as<std::ranges::range_value_t<TXT>, double> &&
std::same_as<std::ranges::range_value_t<TYT>, double> &&
std::same_as<std::ranges::range_value_t<XT>, double> &&
std::same_as<std::ranges::range_value_t<YT>, double> &&
std::same_as<std::ranges::range_value_t<CoeffT>, double> &&
std::same_as<std::ranges::range_value_t<FuncT>, double>,
"Input ranges elements type must be double!");
if constexpr (std::ranges::contiguous_range<WeightT>) {
static_assert(std::same_as<std::ranges::range_value_t<WeightT>, double>,
"Input ranges elements type must be double!");
}
auto m = std::min(std::min(std::ranges::size(tetha), std::ranges::size(phi)), std::ranges::size(func));
if (m < 2) {
if (kx < 0 || ky < 0) {
return 10;
}
int res = 0;
const auto nt = std::ranges::size(tetha_knots);
const auto np = std::ranges::size(phi_knots);
int ier = 0;
// number of knots must be >= 8 for the qubic b-splines
if (std::min(nt, np) < 8) {
int ntx = std::ranges::size(tx);
int nty = std::ranges::size(ty);
auto n_coeffs = (ntx - kx - 1) * (nty - ky - 1);
if (std::ranges::size(coeffs) < n_coeffs) {
return 10;
}
if constexpr (std::ranges::contiguous_range<WeightT>) {
m = std::min(m, std::ranges::size(weight));
if (m < 2) {
return 10;
}
int mx = std::ranges::size(x), my = std::ranges::size(y);
int N = mx * my;
if (std::ranges::size(func) < N) {
std::ranges::fill_n(std::back_inserter(func), N - std::ranges::size(func), 0.0);
}
// compute working arrays sizes according to sphere.f
const int u = nt - 7;
const int v = np - 7;
const int uv = u * v;
const int v2 = v * v;
// compute sizes of working arrays according to bispev.f
int lwrk = mx * (kx + 1) + my * (ky + 1);
std::vector<double> wrk(lwrk);
const int lwrk1 = 185 + 52 * v + 10 * u + 14 * uv + 8 * (u - 1) * v2 + 8 * m;
const int lwrk2 = 48 + 21 * v + 7 * uv + 4 * (u - 1) * v2;
const int kwrk = m + uv;
int kwrk = mx + my;
std::vector<int> iwrk(kwrk);
std::unique_ptr<double> wrk1{new double(lwrk1)};
std::unique_ptr<double> wrk2{new double(lwrk2)};
std::unique_ptr<int> iwrk{new int(kwrk)};
auto tx_ptr = const_cast<double*>(std::ranges::data(tx));
auto ty_ptr = const_cast<double*>(std::ranges::data(ty));
auto coeffs_ptr = const_cast<double*>(std::ranges::data(coeffs));
auto x_ptr = const_cast<double*>(std::ranges::data(x));
auto y_ptr = const_cast<double*>(std::ranges::data(y));
const int n_coeffs = (nt - 4) * (np - 4);
if (std::ranges::size(coeffs) < n_coeffs) { // resize
std::ranges::fill_n(std::back_inserter(coeffs), n_coeffs - std::ranges::size(coeffs), 0.0);
}
bispev(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, x_ptr, &mx, y_ptr, &my, std::ranges::data(func),
wrk.data(), &lwrk, iwrk.data(), &kwrk, &ier);
const int iopt = -1;
const double s = 100.0;
if constexpr (std::ranges::contiguous_range<WeightT>) {
res = sphere(&iopt, &m, std::ranges::data(tetha), std::ranges::data(phi), std::ranges::data(func),
std::ranges::data(weight), &s, &nt, &np, &eps, &nt, std::ranges::data(tetha_knots), &np,
std::ranges::data(phi_knots), std::ranges::data(coeffs), &resi2_sum, wrk1.get(), &lwrk1,
wrk2.get(), &lwrk2, iwrk.get(), &kwrk, &res);
} else {
std::vector<double> weight_vec(m, weight);
res = sphere(&iopt, &m, std::ranges::data(tetha), std::ranges::data(phi), std::ranges::data(func),
weight_vec.data(), &s, &nt, &np, &eps, &nt, std::ranges::data(tetha_knots), &np,
std::ranges::data(phi_knots), std::ranges::data(coeffs), &resi2_sum, wrk1.get(), &lwrk1,
wrk2.get(), &lwrk2, iwrk.get(), &kwrk, &res);
}
return res;
return ier;
}
*/
} // namespace mcc::fitpack