| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (C) 2025 Tiago V. L. Amorim (@tiagovla) | ||
| 2 | // | ||
| 3 | // This file is part of oiseau (https://github.com/tiagovla/oiseau) | ||
| 4 | // | ||
| 5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 6 | |||
| 7 | #include "oiseau/dg/nodal/ref_hexahedron.hpp" | ||
| 8 | |||
| 9 | #include <cstddef> | ||
| 10 | #include <xtensor-blas/xlinalg.hpp> | ||
| 11 | #include <xtensor/core/xshape.hpp> | ||
| 12 | #include <xtensor/core/xtensor_forward.hpp> | ||
| 13 | #include <xtensor/generators/xbuilder.hpp> | ||
| 14 | #include <xtensor/misc/xmanipulation.hpp> | ||
| 15 | #include <xtensor/views/xslice.hpp> | ||
| 16 | #include <xtensor/views/xview.hpp> | ||
| 17 | |||
| 18 | #include "oiseau/dg/nodal/ref_element.hpp" | ||
| 19 | #include "oiseau/dg/nodal/utils.hpp" | ||
| 20 | #include "oiseau/utils/math.hpp" | ||
| 21 | |||
| 22 | namespace oiseau::dg::nodal { | ||
| 23 | |||
| 24 | 14 | RefHexahedron::RefHexahedron(unsigned order) : RefElement(order) { | |
| 25 | 14 | this->m_np = (order + 1) * (order + 1) * (order + 1); | |
| 26 | 14 | this->m_nfp = (order + 1) * (order + 1); | |
| 27 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | this->m_r = detail::generate_hexahedron_nodes(this->m_order); |
| 28 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | this->m_v = this->vandermonde(this->m_r); |
| 29 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | this->m_gv = this->grad_vandermonde(this->m_r); |
| 30 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | this->m_d = this->grad_operator(this->m_v, this->m_gv); |
| 31 | 14 | } | |
| 32 | |||
| 33 | 1312 | xt::xarray<double> RefHexahedron::basis_function(const xt::xarray<double> &rst, int i, int j, | |
| 34 | int k) const { | ||
| 35 |
2/4✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1312 times.
✗ Branch 5 not taken.
|
1312 | xt::xarray<double> r = xt::col(rst, 0); |
| 36 |
2/4✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1312 times.
✗ Branch 5 not taken.
|
1312 | xt::xarray<double> s = xt::col(rst, 1); |
| 37 |
2/4✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1312 times.
✗ Branch 5 not taken.
|
1312 | xt::xarray<double> t = xt::col(rst, 2); |
| 38 | |||
| 39 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto h1 = oiseau::utils::jacobi_p(i, 0.0, 0.0, r); // P_i(r) |
| 40 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto h2 = oiseau::utils::jacobi_p(j, 0.0, 0.0, s); // P_j(s) |
| 41 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto h3 = oiseau::utils::jacobi_p(k, 0.0, 0.0, t); // P_k(t) |
| 42 | |||
| 43 |
1/2✓ Branch 3 taken 1312 times.
✗ Branch 4 not taken.
|
2624 | return h1 * h2 * h3; |
| 44 | 1312 | } | |
| 45 | |||
| 46 | 1312 | xt::xarray<double> RefHexahedron::grad_basis_function(const xt::xarray<double> &rst, int i, int j, | |
| 47 | int k) const { | ||
| 48 |
2/4✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1312 times.
✗ Branch 5 not taken.
|
1312 | xt::xarray<double> r = xt::col(rst, 0); |
| 49 |
2/4✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1312 times.
✗ Branch 5 not taken.
|
1312 | xt::xarray<double> s = xt::col(rst, 1); |
| 50 |
2/4✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1312 times.
✗ Branch 5 not taken.
|
1312 | xt::xarray<double> t = xt::col(rst, 2); |
| 51 | |||
| 52 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto Pi_r = oiseau::utils::jacobi_p(i, 0.0, 0.0, r); // P_i(r) |
| 53 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto Pj_s = oiseau::utils::jacobi_p(j, 0.0, 0.0, s); // P_j(s) |
| 54 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto Pk_t = oiseau::utils::jacobi_p(k, 0.0, 0.0, t); // P_k(t) |
| 55 | |||
| 56 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto dPi_r = oiseau::utils::grad_jacobi_p(i, 0.0, 0.0, r); // dP_i/dr |
| 57 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto dPj_s = oiseau::utils::grad_jacobi_p(j, 0.0, 0.0, s); // dP_j/ds |
| 58 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto dPk_t = oiseau::utils::grad_jacobi_p(k, 0.0, 0.0, t); // dP_k/dt |
| 59 | |||
| 60 | 1312 | auto dphidr = dPi_r * Pj_s * Pk_t; | |
| 61 | 1312 | auto dphids = Pi_r * dPj_s * Pk_t; | |
| 62 | 1312 | auto dphidt = Pi_r * Pj_s * dPk_t; | |
| 63 | |||
| 64 |
2/4✓ Branch 2 taken 1312 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1312 times.
✗ Branch 6 not taken.
|
2624 | return xt::stack(xt::xtuple(dphidr, dphids, dphidt), 1); // shape: [N, 3] |
| 65 | 1312 | } | |
| 66 | |||
| 67 | 14 | xt::xarray<double> RefHexahedron::vandermonde(const xt::xarray<double> &rst) const { | |
| 68 | 14 | const std::size_t n_points = rst.shape()[0]; | |
| 69 | 14 | const std::size_t n_basis = this->m_np; // (order+1)*(order+1)*(order+1) | |
| 70 | |||
| 71 |
2/4✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | xt::xarray<double> output(xt::dynamic_shape<std::size_t>({n_points, n_basis})); |
| 72 | 14 | int index = 0; | |
| 73 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 14 times.
|
72 | for (unsigned i = 0; i <= this->m_order; ++i) { |
| 74 |
2/2✓ Branch 0 taken 266 times.
✓ Branch 1 taken 58 times.
|
324 | for (unsigned j = 0; j <= this->m_order; ++j) { |
| 75 |
2/2✓ Branch 0 taken 1312 times.
✓ Branch 1 taken 266 times.
|
1578 | for (unsigned k = 0; k <= this->m_order; ++k, ++index) { |
| 76 |
3/6✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1312 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1312 times.
✗ Branch 8 not taken.
|
1312 | xt::col(output, index) = this->basis_function(rst, i, j, k); |
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | 14 | return output; | |
| 81 | ✗ | } | |
| 82 | |||
| 83 | 14 | xt::xarray<double> RefHexahedron::grad_vandermonde(const xt::xarray<double> &rst) const { | |
| 84 | 14 | const std::size_t n_points = rst.shape()[0]; | |
| 85 | 14 | const std::size_t n_basis = this->m_np; // (order+1)*(order+1)*(order+1) | |
| 86 | |||
| 87 |
2/4✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | xt::xarray<double> output(xt::dynamic_shape<std::size_t>({n_points, n_basis, 3})); |
| 88 | 14 | std::size_t index = 0; | |
| 89 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 14 times.
|
72 | for (unsigned i = 0; i <= this->m_order; ++i) { |
| 90 |
2/2✓ Branch 0 taken 266 times.
✓ Branch 1 taken 58 times.
|
324 | for (unsigned j = 0; j <= this->m_order; ++j) { |
| 91 |
2/2✓ Branch 0 taken 1312 times.
✓ Branch 1 taken 266 times.
|
1578 | for (unsigned k = 0; k <= this->m_order; ++k, ++index) { |
| 92 |
1/2✓ Branch 1 taken 1312 times.
✗ Branch 2 not taken.
|
1312 | auto tmp = this->grad_basis_function(rst, i, j, k); |
| 93 |
2/4✓ Branch 3 taken 1312 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1312 times.
✗ Branch 7 not taken.
|
1312 | xt::view(output, xt::all(), index, xt::all()) = tmp; |
| 94 | 1312 | } | |
| 95 | } | ||
| 96 | } | ||
| 97 | 14 | return output; | |
| 98 | ✗ | } | |
| 99 | |||
| 100 | 14 | xt::xarray<double> RefHexahedron::grad_operator(const xt::xarray<double> &v, | |
| 101 | const xt::xarray<double> &gv) const { | ||
| 102 |
1/2✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
|
14 | auto gvr = xt::view(gv, xt::all(), xt::all(), 0); |
| 103 |
1/2✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
|
14 | auto gvs = xt::view(gv, xt::all(), xt::all(), 1); |
| 104 |
1/2✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
|
14 | auto gvt = xt::view(gv, xt::all(), xt::all(), 2); |
| 105 | |||
| 106 | 14 | const auto vt = xt::transpose(v); | |
| 107 | 14 | const auto dvt_dr = xt::transpose(gvr); | |
| 108 | 14 | const auto dvt_ds = xt::transpose(gvs); | |
| 109 | 14 | const auto dvt_dt = xt::transpose(gvt); | |
| 110 | |||
| 111 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | const auto dr = xt::transpose(xt::linalg::solve(vt, dvt_dr)); |
| 112 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | const auto ds = xt::transpose(xt::linalg::solve(vt, dvt_ds)); |
| 113 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | const auto dt = xt::transpose(xt::linalg::solve(vt, dvt_dt)); |
| 114 | |||
| 115 |
2/4✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
|
28 | return xt::stack(xt::xtuple(dr, ds, dt), 2); |
| 116 | 14 | } | |
| 117 | |||
| 118 | } // namespace oiseau::dg::nodal | ||
| 119 | |||
| 120 | namespace oiseau::dg::nodal::detail { | ||
| 121 | 14 | xt::xarray<double> generate_hexahedron_nodes(unsigned order) { | |
| 122 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | xt::xarray<double> r1d = utils::jacobi_gl(order, 0.0, 0.0); |
| 123 | 14 | auto [R, S, T] = xt::meshgrid(r1d, r1d, r1d); | |
| 124 |
5/10✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 14 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 14 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 14 times.
✗ Branch 15 not taken.
|
28 | return xt::stack(xt::xtuple(xt::flatten(R), xt::flatten(S), xt::flatten(T)), 1); |
| 125 | 14 | } | |
| 126 | |||
| 127 | } // namespace oiseau::dg::nodal::detail | ||
| 128 |