27template <
typename Derived>
auto diff(
const Eigen::MatrixBase<Derived> &v) {
29 return (v.tail(v.size() - 1) - v.head(v.size() - 1));
43template <
typename DerivedY,
typename DerivedX>
44auto trapz(
const Eigen::MatrixBase<DerivedY> &y,
const Eigen::MatrixBase<DerivedX> &x) {
45 auto dx = (x.tail(x.size() - 1) - x.head(x.size() - 1));
46 auto mean_y = 0.5 * (y.tail(y.size() - 1) + y.head(y.size() - 1));
49 return (mean_y.array() * dx.array()).sum();
65template <
typename DerivedY,
typename DerivedX>
66auto cumtrapz(
const Eigen::MatrixBase<DerivedY> &y,
const Eigen::MatrixBase<DerivedX> &x) {
67 using Scalar = std::decay_t<
decltype(0.5 *
68 (std::declval<typename DerivedY::Scalar>() +
69 std::declval<typename DerivedY::Scalar>()) *
70 (std::declval<typename DerivedX::Scalar>() -
71 std::declval<typename DerivedX::Scalar>()))>;
74 if (y.size() != x.size()) {
82 result(0) = Scalar(0.0);
83 for (Eigen::Index i = 1; i < y.size(); ++i) {
84 const auto interval = 0.5 * (y(i - 1) + y(i)) * (x(i) - x(i - 1));
85 result(i) = result(i - 1) + interval;
103template <
typename DerivedY, JanusScalar Spacing =
double>
104auto cumtrapz(
const Eigen::MatrixBase<DerivedY> &y,
const Spacing &dx = 1.0) {
105 using Scalar = std::decay_t<
decltype(0.5 *
106 (std::declval<typename DerivedY::Scalar>() +
107 std::declval<typename DerivedY::Scalar>()) *
108 std::declval<Spacing>())>;
115 result(0) = Scalar(0.0);
116 for (Eigen::Index i = 1; i < y.size(); ++i) {
117 const auto interval = 0.5 * (y(i - 1) + y(i)) * dx;
118 result(i) = result(i - 1) + interval;
138template <
typename DerivedY,
typename DerivedX>
139auto gradient_1d(
const Eigen::MatrixBase<DerivedY> &y,
const Eigen::MatrixBase<DerivedX> &x) {
140 Eigen::Index n = y.size();
141 typename DerivedY::PlainObject grad(n);
151 grad.segment(1, n - 2) =
152 (y.tail(n - 2) - y.head(n - 2)).array() / (x.tail(n - 2) - x.head(n - 2)).array();
157 grad(0) = (y(1) - y(0)) / (x(1) - x(0));
159 grad(n - 1) = (y(n - 1) - y(n - 2)) / (x(n - 1) - x(n - 2));
177template <
typename DerivedF,
typename Spacing =
double>
178auto gradient(
const Eigen::MatrixBase<DerivedF> &f,
const Spacing &dx = 1.0,
int edge_order = 1,
180 using Scalar =
typename DerivedF::Scalar;
183 Eigen::Index N = f.size();
193 Vector dx_vec(N - 1);
194 if constexpr (std::is_arithmetic_v<Spacing>) {
195 dx_vec.setConstant(dx);
198 if (dx.size() == N) {
200 dx_vec = (dx.tail(N - 1) - dx.head(N - 1));
201 }
else if (dx.size() == N - 1) {
205 throw InvalidArgument(
"gradient: dx must be scalar, size N, or size N-1");
211 grad(0) = (f(1) - f(0)) / dx_vec(0);
219 Vector hm = dx_vec.head(N - 2);
220 Vector hp = dx_vec.tail(N - 2);
225 Vector dfp = f.tail(N - 2) - f.segment(1, N - 2);
226 Vector dfm = f.segment(1, N - 2) - f.head(N - 2);
231 grad.segment(1, N - 2) =
232 (hm.array().
square() * dfp.array() + hp.array().square() * dfm.array()) /
233 (hm.array() * hp.array() * (hm.array() + hp.array()));
235 if (edge_order == 1) {
237 grad(0) = dfm(0) / hm(0);
238 grad(N - 1) = dfp(N - 3) / hp(N - 3);
240 }
else if (edge_order == 2) {
243 Scalar dfm_0 = dfm(0);
244 Scalar dfp_0 = dfp(0);
247 grad(0) = (2.0 * dfm_0 * hm_0 * hp_0 + dfm_0 * hp_0 * hp_0 - dfp_0 * hm_0 * hm_0) /
248 (hm_0 * hp_0 * (hm_0 + hp_0));
251 Scalar dfm_N = dfm(N - 3);
252 Scalar dfp_N = dfp(N - 3);
253 Scalar hm_N = hm(N - 3);
254 Scalar hp_N = hp(N - 3);
255 grad(N - 1) = (-dfm_N * hp_N * hp_N + dfp_N * hm_N * hm_N + 2.0 * dfp_N * hm_N * hp_N) /
256 (hm_N * hp_N * (hm_N + hp_N));
263 grad.segment(1, N - 2) =
264 2.0 / (hm.array() + hp.array()) * (dfp.array() / hp.array() - dfm.array() / hm.array());
268 grad(N - 1) = grad(N - 2);
271 throw InvalidArgument(
"gradient: derivative order (n) must be 1 or 2");
294template <
typename DerivedF,
typename Spacing =
double,
typename Period>
296 const Period &period,
int edge_order = 1,
int n = 1) {
297 using Scalar =
typename DerivedF::Scalar;
300 const Eigen::Index N = f.size();
303 if (edge_order != 1 && edge_order != 2) {
306 if (n != 1 && n != 2) {
307 throw InvalidArgument(
"gradient_periodic: derivative order (n) must be 1 or 2");
316 Eigen::VectorXd dx_vec(N - 1);
317 if constexpr (std::is_arithmetic_v<Spacing>) {
318 dx_vec.setConstant(
static_cast<double>(dx));
320 if (dx.size() == N) {
321 for (Eigen::Index i = 0; i < N - 1; ++i) {
322 dx_vec(i) =
static_cast<double>(dx(i + 1) - dx(i));
324 }
else if (dx.size() == N - 1) {
325 for (Eigen::Index i = 0; i < N - 1; ++i) {
326 dx_vec(i) =
static_cast<double>(dx(i));
329 throw InvalidArgument(
"gradient_periodic: dx must be scalar, size N, or size N-1");
335 grad(0) = (f(1) - f(0)) / dx_vec(0);
343 const double wrap_dx =
static_cast<double>(period) - dx_vec.sum();
344 if (wrap_dx <= 0.0) {
345 throw InvalidArgument(
"gradient_periodic: period must exceed the covered span. Exclude "
346 "duplicate endpoint samples.");
349 for (Eigen::Index i = 0; i < N; ++i) {
350 const Eigen::Index prev = (i == 0) ? N - 1 : i - 1;
351 const Eigen::Index next = (i == N - 1) ? 0 : i + 1;
353 const double hm = (i == 0) ? wrap_dx : dx_vec(i - 1);
354 const double hp = (i == N - 1) ? wrap_dx : dx_vec(i);
356 const auto dfm = f(i) - f(prev);
357 const auto dfp = f(next) - f(i);
360 grad(i) = (hm * hm * dfp + hp * hp * dfm) / (hm * hp * (hm + hp));
362 grad(i) = 2.0 / (hm + hp) * (dfp / hp - dfm / hm);
Scalar and element-wise arithmetic functions (abs, sqrt, pow, exp, log, etc.).
C++20 concepts constraining valid Janus scalar types.
Custom exception hierarchy for Janus framework.
Input validation failed (e.g., mismatched sizes, invalid parameters).
Definition JanusError.hpp:31
Definition Diagnostics.hpp:19
auto gradient(const Eigen::MatrixBase< DerivedF > &f, const Spacing &dx=1.0, int edge_order=1, int n=1)
Computes gradient using second-order accurate central differences.
Definition Calculus.hpp:178
auto gradient_1d(const Eigen::MatrixBase< DerivedY > &y, const Eigen::MatrixBase< DerivedX > &x)
Computes gradient of 1D data using central differences.
Definition Calculus.hpp:139
T square(const T &x)
Computes x^2 (more efficient than pow(x, 2)).
Definition Arithmetic.hpp:739
auto gradient_periodic(const Eigen::MatrixBase< DerivedF > &f, const Spacing &dx, const Period &period, int edge_order=1, int n=1)
Computes gradient with periodic boundary conditions.
Definition Calculus.hpp:295
auto diff(const Eigen::MatrixBase< Derived > &v)
Computes adjacent differences of a vector Returns a vector of size N-1 where out[i] = v[i+1] - v[i].
Definition Calculus.hpp:27
auto trapz(const Eigen::MatrixBase< DerivedY > &y, const Eigen::MatrixBase< DerivedX > &x)
Computes trapezoidal integration Approximation of integral of y(x) using trapezoidal rule.
Definition Calculus.hpp:44
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > JanusVector
Dynamic-size column vector for both numeric and symbolic backends.
Definition JanusTypes.hpp:49
auto cumtrapz(const Eigen::MatrixBase< DerivedY > &y, const Eigen::MatrixBase< DerivedX > &x)
Computes the cumulative trapezoidal integral.
Definition Calculus.hpp:66