// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // debye.hpp // Debye functions (solid-state physics) // // Provided functions: // debye(n, x) — Debye function D_n(x) = (n/x^n) ∫₀ˣ t^n/(e^t - 1) dt // debye1(x) — D_1(x) // debye2(x) — D_2(x) // debye3(x) — D_3(x) (specific heat) // debye4(x) — D_4(x) (enthalpy) // // Supported types: float, double, long double #ifndef SANGI_SPECIAL_DEBYE_HPP #define SANGI_SPECIAL_DEBYE_HPP #include #include #include #include namespace sangi { namespace special { // ================================================================ // Debye function D_n(x) = (n/x^n) ∫₀ˣ t^n/(e^t - 1) dt // ================================================================ namespace detail { template T debye_series(int n, T x) { // For small x: Taylor series // D_n(x) = 1 - n·x/(2(n+1)) + Σ_{k=1}^∞ B_{2k}·n!·x^{2k} / ((n+2k)·(2k)!) // where B_{2k} are the Bernoulli numbers // // Simplified version: compute ∫₀ˣ t^n/(e^t-1) dt directly via Gauss-Legendre // Integral: ∫₀ˣ t^n/(e^t - 1) dt // The integrand is asymptotic to t^{n-1} as t→0 (integrable) // 15-point Gauss-Legendre on [0, x] // Substitution: t = x·(u+1)/2, dt = x/2 du, u ∈ [-1, 1] constexpr T gl_nodes[] = { T(-0.98799251802048543), T(-0.93727339240070591), T(-0.84820658341042722), T(-0.72441773136017005), T(-0.57097217260853885), T(-0.39415134707756337), T(-0.20119409399743452), T(0.0), T(0.20119409399743452), T(0.39415134707756337), T(0.57097217260853885), T(0.72441773136017005), T(0.84820658341042722), T(0.93727339240070591), T(0.98799251802048543) }; constexpr T gl_weights[] = { T(0.03075324199611727), T(0.07036604748890871), T(0.10715922046717194), T(0.13957067792615431), T(0.16626920581699393), T(0.18616100001556222), T(0.19843148532711158), T(0.20257824192556127), T(0.19843148532711158), T(0.18616100001556222), T(0.16626920581699393), T(0.13957067792615431), T(0.10715922046717194), T(0.07036604748890871), T(0.03075324199611727) }; T sum = T(0); T half_x = x / T(2); for (int i = 0; i < 15; ++i) { T t = half_x * (gl_nodes[i] + T(1)); if (t < T(1e-15)) continue; T integrand; if (t > T(500)) { integrand = std::pow(t, T(n)) * std::exp(-t); } else { integrand = std::pow(t, T(n)) / (std::exp(t) - T(1)); } sum += gl_weights[i] * integrand; } sum *= half_x; // D_n(x) = n / x^n · integral return T(n) / std::pow(x, T(n)) * sum; } } // namespace detail /// Debye function D_n(x) template [[nodiscard]] T debye(int n, T x) { if (std::isnan(x)) return std::numeric_limits::quiet_NaN(); if (n < 1) return std::numeric_limits::quiet_NaN(); if (x < T(0)) return std::numeric_limits::quiet_NaN(); if (x == T(0)) return T(1); // D_n(0) = 1 // For very large x: D_n(x) → n!/x^n · ζ(n+1) · Γ(n+1) ... // Asymptotic: D_n(x) → n · n! · ζ(n+1) / x^n (x → ∞) return detail::debye_series(n, x); } template [[nodiscard]] T debye1(T x) { return debye(1, x); } template [[nodiscard]] T debye2(T x) { return debye(2, x); } template [[nodiscard]] T debye3(T x) { return debye(3, x); } template [[nodiscard]] T debye4(T x) { return debye(4, x); } } // namespace special } // namespace sangi #endif // SANGI_SPECIAL_DEBYE_HPP