29 const auto n{grid.size()};
30 const auto [grid_min, grid_max] = std::ranges::minmax(grid);
31 const auto grid_range{grid_max - grid_min};
32 auto quadrature = std::vector<std::array<double, 2>>{
33 {-1., (grid[1] - grid[0]) / grid_range},
35 std::ranges::transform(
36 std::views::iota(1U, n - 1), std::back_inserter(quadrature),
37 [grid, gm = grid_min, grid_range](
auto i) {
39 2. * (grid[i] - gm) / grid_range - 1., (grid[i + 1] - grid[i - 1]) / grid_range
43 quadrature.push_back({1., (grid[n - 1] - grid[n - 2]) / grid_range});
48 std::span<const double> grid,
size_t order
50 const auto n{grid.size()};
51 const auto [grid_min, grid_max] = std::ranges::minmax(grid);
52 const auto grid_range{grid_max - grid_min};
54 const auto sectional_num_nodes = sectional_weights.size();
55 const auto num_sections = (n - 1) / (sectional_num_nodes - 1);
57 auto quadrature = std::vector<std::array<double, 2>>{};
58 std::ranges::transform(
59 grid, std::back_inserter(quadrature),
60 [gm = grid_min, grid_range](
auto grid_location) {
61 return std::array{2. * (grid_location - gm) / grid_range - 1., 0.};
65 auto section_index = 0UL;
66 for ([[maybe_unused]]
auto section : std::views::iota(0U, num_sections)) {
67 const auto section_range =
68 grid[section_index + sectional_num_nodes - 1] - grid[section_index];
69 const auto weight_scaling = section_range / grid_range;
70 for (
auto node : std::views::iota(0U, sectional_num_nodes)) {
71 quadrature[section_index + node][1] += sectional_weights[node] * weight_scaling;
73 section_index += sectional_num_nodes - 1UL;
89 constexpr auto max_iterations = 1000U;
90 constexpr auto convergence_tolerance = std::numeric_limits<double>::epsilon();
97 const size_t n_points{order};
98 const size_t n_unique{(n_points + 1) / 2};
99 std::vector<double> points(n_points, 0.);
100 std::vector<double> weights(n_points, 0.);
103 for (
auto i_GL_point : std::views::iota(0U, n_unique)) {
105 auto x_it = std::cos(
106 std::numbers::pi * (
static_cast<double>(i_GL_point) + 0.75) /
107 (
static_cast<double>(n_points) + 0.5)
111 bool converged =
false;
112 for ([[maybe_unused]]
auto iteration : std::views::iota(0U, max_iterations)) {
113 const auto x_old = x_it;
120 const auto p_n_prime =
121 static_cast<double>(n_points) * (x_it * p_n - p_n_minus_1) / (x_it * x_it - 1.);
124 x_it -= p_n / p_n_prime;
127 if (std::abs(x_it - x_old) <= convergence_tolerance) {
133 throw std::runtime_error(
134 "Newton-Raphson failed to converge for GL point " + std::to_string(i_GL_point) +
135 " of order " + std::to_string(n_points)
140 points[i_GL_point] = -x_it;
141 points[n_points - 1 - i_GL_point] = x_it;
146 const auto p_n_prime =
147 static_cast<double>(n_points) * (x_it * p_n - p_n_minus_1) / (x_it * x_it - 1.);
148 const auto weight = 2. / ((1. - x_it * x_it) * p_n_prime * p_n_prime);
151 weights[i_GL_point] = weight;
152 weights[n_points - 1 - i_GL_point] = weight;
156 auto quadrature = std::vector<std::array<double, 2>>(n_points);
157 for (
auto i_GL_point : std::views::iota(0U, n_points)) {
158 quadrature[i_GL_point] = {points[i_GL_point], weights[i_GL_point]};
160 std::ranges::sort(quadrature, [](
const auto& a,
const auto& b) {