diff --git a/himan-lib/include/numerical_functions.h b/himan-lib/include/numerical_functions.h index f047de56..9514bfc2 100644 --- a/himan-lib/include/numerical_functions.h +++ b/himan-lib/include/numerical_functions.h @@ -191,7 +191,7 @@ std::vector Arange(T start, T stop, T step) ret[0] = start; - std::generate(ret.begin() + 1, ret.end(), [ v = ret[0], &step ]() mutable { return v += step; }); + std::generate(ret.begin() + 1, ret.end(), [v = ret[0], &step]() mutable { return v += step; }); return ret; } @@ -235,7 +235,7 @@ std::vector> Linspace(const std::vector& start, const std::vec ret[i].resize(static_cast(length)); ret[i][0] = start[i]; - std::generate(ret[i].begin() + 1, ret[i].end(), [ v = ret[i][0], &step ]() mutable { return v += step; }); + std::generate(ret[i].begin() + 1, ret[i].end(), [v = ret[i][0], &step]() mutable { return v += step; }); } return ret; @@ -278,10 +278,30 @@ namespace interpolation * Basic interpolation functions. */ +template +CUDA_HOST CUDA_DEVICE inline Type NearestPoint(Type factor, Type Y1, Type Y2) +{ + if (factor < 0.5) + { + return Y1; + } + else + { + return Y2; + } +} + +template +CUDA_HOST CUDA_DEVICE inline Type NearestPoint(Type X, Type X1, Type X2, Type Y1, Type Y2) +{ + const Type factor = static_cast((X - X1) / (X2 - X1)); + return NearestPoint(factor, Y1, Y2); +} + template CUDA_HOST CUDA_DEVICE inline Type Linear(Type factor, Type Y1, Type Y2) { - return static_cast (std::fma(factor, Y2, std::fma(-factor, Y1, Y1))); + return static_cast(std::fma(factor, Y2, std::fma(-factor, Y1, Y1))); } template @@ -292,7 +312,7 @@ CUDA_HOST CUDA_DEVICE inline Type Linear(Type X, Type X1, Type X2, Type Y1, Type return Y1; } - const Type factor = static_cast ((X - X1) / (X2 - X1)); + const Type factor = static_cast((X - X1) / (X2 - X1)); return Linear(factor, Y1, Y2); } @@ -309,6 +329,30 @@ CUDA_HOST CUDA_DEVICE inline Type BiLinear(Type dx, Type dy, Type a, Type b, Typ return (1 - dx) * (1 - dy) * c + dx * (1 - dy) * d + (1 - dx) * dy * a + dx * dy * b; } +/** + * @brief Linear interpolation of angles, can deal with modulo 360 + */ + +template +CUDA_HOST CUDA_DEVICE inline Type LinearAngle(Type factor, Type Y1, Type Y2) +{ + ASSERT(factor >= 0 && factor <= 1); + + // cast to double so that can use fmod() + double y1 = static_cast(Y1); + double y2 = static_cast(Y2); + + const double shortest_angle = fmod(fmod((y2 - y1), 360.) + 540., 360.) - 180.; + + return static_cast(fmod(y1 + shortest_angle * factor + 360., 360.)); +} + +template +CUDA_HOST CUDA_DEVICE inline Type LinearAngle(Type X, Type X1, Type X2, Type Y1, Type Y2) +{ + const Type factor = static_cast((X - X1) / (X2 - X1)); + return LinearAngle(factor, Y1, Y2); +} } // namespace interpolation } // namespace numerical_functions diff --git a/himan-plugins/source/luatool.cpp b/himan-plugins/source/luatool.cpp index 7cc40a09..688388c2 100644 --- a/himan-plugins/source/luatool.cpp +++ b/himan-plugins/source/luatool.cpp @@ -1179,6 +1179,79 @@ matrix ProbLimitEq2D(const matrix& A, const matrix& B, T limit) } } // namespace luabind_workaround +namespace numerical_functions_wrapper +{ +template +object Linear(const object& X, const object& X1, const object& X2, const object& Y1, const object& Y2) +{ + auto x = TableToVector(X); + auto x1 = TableToVector(X1); + auto x2 = TableToVector(X2); + auto y1 = TableToVector(Y1); + auto y2 = TableToVector(Y2); + + if (y1.size() != y2.size()) + { + throw std::runtime_error("luatool::Linear Y1 and Y2 must be of same size"); + } + + std::vector interp(y1.size()); + for (size_t i = 0; i < y1.size(); i++) + { + interp[i] = numerical_functions::interpolation::Linear(x[i], x1[i], x2[i], y1[i], y2[i]); + } + + return VectorToTable(interp); +} + +template +object LinearAngle(const object& X, const object& X1, const object& X2, const object& Y1, const object& Y2) +{ + auto x = TableToVector(X); + auto x1 = TableToVector(X1); + auto x2 = TableToVector(X2); + auto y1 = TableToVector(Y1); + auto y2 = TableToVector(Y2); + + if (y1.size() != y2.size()) + { + throw std::runtime_error("luatool::LinearAngle Y1 and Y2 must be of same size"); + } + + std::vector interp(y1.size()); + for (size_t i = 0; i < y1.size(); i++) + { + interp[i] = numerical_functions::interpolation::LinearAngle(x[i], x1[i], x2[i], y1[i], y2[i]); + } + + return VectorToTable(interp); +} + +template +object NearestPoint(const object& X, const object& X1, const object& X2, const object& Y1, const object& Y2) +{ + auto x = TableToVector(X); + auto x1 = TableToVector(X1); + auto x2 = TableToVector(X2); + auto y1 = TableToVector(Y1); + auto y2 = TableToVector(Y2); + + if (y1.size() != y2.size()) + { + throw std::runtime_error("luatool::NearestPoint Y1 and Y2 must be of same size"); + } + + std::vector interp(y1.size()); + for (size_t i = 0; i < y1.size(); i++) + { + interp[i] = numerical_functions::interpolation::NearestPoint(x[i], x1[i], x2[i], y1[i], y2[i]); + } + + return VectorToTable(interp); +} + +} // namespace numerical_functions_wrapper + namespace params_wrapper { params create(const object& table) @@ -1639,6 +1712,9 @@ void BindLib(lua_State* L) def("Max2D", &numerical_functions::Max2D), def("Min2D", &numerical_functions::Min2D), def("Min2D", &numerical_functions::Min2D), + def("Linear", &numerical_functions_wrapper::Linear), + def("LinearAngle", &numerical_functions_wrapper::LinearAngle), + def("NearestPoint", &numerical_functions_wrapper::NearestPoint), def("ProbLimitGt2D", &luabind_workaround::ProbLimitGt2D), def("ProbLimitGt2D", &luabind_workaround::ProbLimitGt2D), def("ProbLimitGe2D", &luabind_workaround::ProbLimitGe2D),