Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cpp/basix/cell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ cell::geometry(cell::type celltype)
0.0, 1.0, 0.0, 1.0, 1.0},
{6, 3}};
case cell::type::pyramid:
return {{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0,
return {{-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0,
0.0, 1.0},
{5, 3}};
case cell::type::hexahedron:
Expand Down
4 changes: 2 additions & 2 deletions cpp/basix/lattice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,8 +750,8 @@ create_pyramid_equispaced(int n, bool exterior)
{
for (int i = 0; i < n + 1 - k; ++i)
{
x(c, 0) = h * (i + b);
x(c, 1) = h * (j + b);
x(c, 0) = 2.0 * h * (i + b) - 1.0;
x(c, 1) = 2.0 * h * (j + b) - 1.0;
x(c, 2) = h * (k + b);
c++;
}
Expand Down
262 changes: 230 additions & 32 deletions cpp/basix/polyset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2028,7 +2028,7 @@ void tabulate_polyset_pyramid_derivs(
// https://doi.org/10.5281/zenodo.15281516 (Scroggs, 2025)
assert(x.extent(1) == 3);
assert(P.extent(0) == (nderiv + 1) * (nderiv + 2) * (nderiv + 3) / 6);
assert(P.extent(1) == (n + 1) * (n + 2) * (2 * n + 3) / 6);
assert(P.extent(1) == (n + 1) * (n + 2) * (2 * n + 3) / 6 * 4);
assert(P.extent(2) == x.extent(0));

// Indexing for pyramidal basis functions
Expand All @@ -2049,7 +2049,7 @@ void tabulate_polyset_pyramid_derivs(
if (n == 0)
{
for (std::size_t j = 0; j < P.extent(2); ++j)
P(idx(0, 0, 0), pyr_idx(0, 0, 0), j) = std::sqrt(3);
P(idx(0, 0, 0), pyr_idx(0, 0, 0), j) = std::sqrt(3) / 2.0;
return;
}

Expand All @@ -2073,24 +2073,17 @@ void tabulate_polyset_pyramid_derivs(
auto p1 = md::submdspan(P, idx(kx, ky, kz), pyr_idx(p - 1, 0, 0),
md::full_extent);
for (std::size_t i = 0; i < p00.size(); ++i)
p00[i] = (a + 1.0) * (x0[i] * 2.0 + x2[i] - 1.0) * p1[i];
p00[i] = (a + 1.0) * x0[i] * p1[i];

if (kx > 0)
{
auto p11 = md::submdspan(P, idx(kx - 1, ky, kz),
pyr_idx(p - 1, 0, 0), md::full_extent);

for (std::size_t i = 0; i < p00.size(); ++i)
p00[i] += (a + 1.0) * 2.0 * kx * p11[i];
p00[i] += (a + 1.0) * kx * p11[i];
}

if (kz > 0)
{
auto pz = md::submdspan(P, idx(kx, ky, kz - 1),
pyr_idx(p - 1, 0, 0), md::full_extent);
for (std::size_t i = 0; i < p00.size(); ++i)
p00[i] += (a + 1.0) * kz * pz[i];
}
if (p > 1)
{
auto p2 = md::submdspan(P, idx(kx, ky, kz), pyr_idx(p - 2, 0, 0),
Expand Down Expand Up @@ -2132,13 +2125,13 @@ void tabulate_polyset_pyramid_derivs(
for (std::size_t i = 0; i < r_pq.size(); ++i)
{
const T x1over = x2[i] == 1.0 ? 0.0 : x1[i] / (1.0 - x2[i]);
r_pq[i] = (a + 1.0) * (2.0 * x1over - 1.0) * _p[i];
r_pq[i] = (a + 1.0) * x1over * _p[i];
}
}
else
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] = (a + 1.0) * (2.0 * x1[i] + x2[i] - 1.0) * _p[i];
r_pq[i] = (a + 1.0) * x1[i] * _p[i];
}
if (ky > 0)
{
Expand All @@ -2149,44 +2142,231 @@ void tabulate_polyset_pyramid_derivs(
for (std::size_t i = 0; i < r_pq.size(); ++i)
{
const T over_z = x2[i] == 1.0 ? 1.0 : 1.0 / (1.0 - x2[i]);
r_pq[i] += 2.0 * (a + 1.0) * ky * over_z * _p[i];
r_pq[i] += (a + 1.0) * ky * over_z * _p[i];
}
}
else
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] += 2.0 * (a + 1.0) * ky * _p[i];
r_pq[i] += (a + 1.0) * ky * _p[i];
}
}

if (kz > 0)
if (kz > 0 and q <= p)
{

auto _p = md::submdspan(P, idx(kx, ky, kz - 1),
pyr_idx(p, q, 0), md::full_extent);
for (std::size_t i = 0; i < r_pq.size(); ++i)
{
const T over_z = x2[i] == 1.0 ? 1.0 : 1.0 / (1.0 - x2[i]);
r_pq[i] += kz * over_z * _p[i];
}
}

if (q > 1)
{
auto _p = md::submdspan(P, idx(kx, ky, kz), pyr_idx(p, q - 2, 0),
md::full_extent);
if (q <= p)
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] -= a * _p[i];
}
else if (q == p + 1)
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] -= a * (1.0 - x2[i]) * _p[i];
}
else
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
{
const T f2 = 1.0 - x2[i];
r_pq[i] -= a * f2 * f2 * _p[i];
}
}
if (kz > 0)
{
auto _p = md::submdspan(P, idx(kx, ky, kz - 1),
pyr_idx(p, q, 0), md::full_extent);
auto _p1 = md::submdspan(P, idx(kx, ky, kz - 1),
pyr_idx(p, q - 1, 0), md::full_extent);
pyr_idx(p, q - 2, 0), md::full_extent);
if (q <= p)
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
{
const T over_z = x2[i] == 1.0 ? 1.0 : 1.0 / (1.0 - x2[i]);
r_pq[i] += kz * a * over_z * _p[i];
}
}
else if (q == p + 1)
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] += kz * a * _p[i];
}
else
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] -= 2.0 * kz * a * (x2[i] - 1.0) * _p[i];
}
}
if (kz > 1 && q > p + 1)
{
auto _p = md::submdspan(P, idx(kx, ky, kz - 2),
pyr_idx(p, q - 2, 0), md::full_extent);
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] -= kz * (kz - 1.0) * a * _p[i];
}
}
}
}

// Extend into r > 0
for (std::size_t r = 1; r <= n; ++r)
{
for (std::size_t p = 0; p <= n - r; ++p)
{
for (std::size_t q = 0; q <= n - r; ++q)
{
auto [ar, br, cr] = jrc<T>(2 * std::max(p, q) + 2, r - 1);
auto r_pqr = md::submdspan(P, idx(kx, ky, kz), pyr_idx(p, q, r),
md::full_extent);
auto _r0 = md::submdspan(P, idx(kx, ky, kz), pyr_idx(p, q, r - 1),
md::full_extent);
for (std::size_t i = 0; i < r_pqr.size(); ++i)
r_pqr[i] = _r0[i] * (2.0 * x2[i] * ar + br - ar);
if (r > 1)
{
auto _r = md::submdspan(P, idx(kx, ky, kz),
pyr_idx(p, q, r - 2), md::full_extent);
for (std::size_t i = 0; i < r_pqr.size(); ++i)
r_pqr[i] -= _r[i] * cr;
}

if (kz > 0)
{
auto _r = md::submdspan(P, idx(kx, ky, kz - 1),
pyr_idx(p, q, r - 1), md::full_extent);
for (std::size_t i = 0; i < r_pqr.size(); ++i)
r_pqr[i] += 2.0 * ar * kz * _r[i];
}
}
}
}
}
}
}

for (std::size_t kx = 0; kx <= 1; ++kx)
{
for (std::size_t ky = 0; ky <= 1 - kx; ++ky)
{
for (std::size_t kz = 1 - kx - ky; kz <= 1 - kx - ky; ++kz)
{
// r = 0
for (std::size_t p = 0; p <= n; ++p)
{
if (p > 0)
{
const T a = static_cast<T>(p - 1) / static_cast<T>(p);
auto p00 = md::submdspan(P, 0 , pyr_idx(p, 0, 0) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);
auto p1 = md::submdspan(P, 0, pyr_idx(p - 1, 0, 0) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);
for (std::size_t i = 0; i < p00.size(); ++i)
p00[i] = (a + 1.0) * x0[i] * p1[i];

if (kx > 0)
{
auto p11 = md::submdspan(P, idx(kx - 1, ky, kz),
pyr_idx(p - 1, 0, 0), md::full_extent);

for (std::size_t i = 0; i < p00.size(); ++i)
p00[i] += (a + 1.0) * kx * p11[i];
}

if (p > 1)
{
auto p2 = md::submdspan(P, 0, pyr_idx(p - 2, 0, 0) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);
for (std::size_t i = 0; i < p00.size(); ++i)
{
T f2 = 1.0 - x2[i];
p00[i] -= a * f2 * f2 * p2[i];
}
if (kz > 0)
{
auto p2z = md::submdspan(P, idx(kx, ky, kz - 1),
pyr_idx(p - 2, 0, 0), md::full_extent);
for (std::size_t i = 0; i < p00.size(); ++i)
p00[i] += 2.0 * a * kz * (1.0 - x2[i]) * p2z[i];
}

if (kz > 1)
{
// quadratic term in z
auto pz = md::submdspan(P, idx(kx, ky, kz - 2),
pyr_idx(p - 2, 0, 0), md::full_extent);
for (std::size_t i = 0; i < p00.size(); ++i)
p00[i] -= a * kz * (kz - 1) * pz[i];
}
}
}

for (std::size_t q = 1; q < n + 1; ++q)
{
const T a = static_cast<T>(q - 1) / static_cast<T>(q);
auto r_pq = md::submdspan(P, 0, pyr_idx(p, q, 0) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);

auto _p = md::submdspan(P, 0, pyr_idx(p, q - 1, 0) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);
if (q <= p)
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
{
const T x1over = x2[i] == 1.0 ? 0.0 : x1[i] / (1.0 - x2[i]);
r_pq[i] = (a + 1.0) * x1over * _p[i];
}
}
else
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] = (a + 1.0) * x1[i] * _p[i];
}
if (ky > 0)
{
auto _p = md::submdspan(P, idx(kx, ky - 1, kz),
pyr_idx(p, q - 1, 0), md::full_extent);
if (q <= p)
{
for (std::size_t i = 0; i < r_pq.size(); ++i)
{
const T over_z = x2[i] == 1.0 ? 1.0 : 1.0 / (1.0 - x2[i]);
r_pq[i] += kz * over_z * ((a + 1.0) * _p1[i] + _p[i]);
r_pq[i] += (a + 1.0) * ky * over_z * _p[i];
}
}
else
{
auto _p1 = md::submdspan(P, idx(kx, ky, kz - 1),
pyr_idx(p, q - 1, 0), md::full_extent);
for (std::size_t i = 0; i < r_pq.size(); ++i)
r_pq[i] += (a + 1.0) * ky * _p[i];
}
}

if (kz > 0 and q <= p)
{

auto _p = md::submdspan(P, idx(kx, ky, kz - 1),
pyr_idx(p, q, 0), md::full_extent);
for (std::size_t i = 0; i < r_pq.size(); ++i)
{
r_pq[i] += (a + 1.0) * kz * _p1[i];
const T over_z = x2[i] == 1.0 ? 1.0 : 1.0 / (1.0 - x2[i]);
r_pq[i] += kz * over_z * _p[i];
}
}
}

if (q > 1)
{
auto _p = md::submdspan(P, idx(kx, ky, kz), pyr_idx(p, q - 2, 0),
auto _p = md::submdspan(P, 0, pyr_idx(p, q - 2, 0) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);
if (q <= p)
{
Expand Down Expand Up @@ -2248,16 +2428,16 @@ void tabulate_polyset_pyramid_derivs(
for (std::size_t q = 0; q <= n - r; ++q)
{
auto [ar, br, cr] = jrc<T>(2 * std::max(p, q) + 2, r - 1);
auto r_pqr = md::submdspan(P, idx(kx, ky, kz), pyr_idx(p, q, r),
auto r_pqr = md::submdspan(P, 0, pyr_idx(p, q, r) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);
auto _r0 = md::submdspan(P, idx(kx, ky, kz), pyr_idx(p, q, r - 1),
auto _r0 = md::submdspan(P, 0, pyr_idx(p, q, r - 1) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);
for (std::size_t i = 0; i < r_pqr.size(); ++i)
r_pqr[i] = _r0[i] * (2.0 * x2[i] * ar + br - ar);
if (r > 1)
{
auto _r = md::submdspan(P, idx(kx, ky, kz),
pyr_idx(p, q, r - 2), md::full_extent);
auto _r = md::submdspan(P, 0, pyr_idx(p, q, r - 2) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * idx(kx, ky, kz),
md::full_extent);
for (std::size_t i = 0; i < r_pqr.size(); ++i)
r_pqr[i] -= _r[i] * cr;
}
Expand Down Expand Up @@ -2287,11 +2467,29 @@ void tabulate_polyset_pyramid_derivs(
for (std::size_t i = 0; i < pqr.extent(0); ++i)
for (std::size_t j = 0; j < pqr.extent(1); ++j)
pqr(i, j) *= std::sqrt(2 * (q + 0.5) * (p + 0.5)
* (std::max(p, q) + r + 1.5))
* 2;
* (std::max(p, q) + r + 1.5));
}
}
}

for (std::size_t r = 0; r <= n; ++r)
{
for (std::size_t p = 0; p <= n - r; ++p)
{
for (std::size_t q = 0; q <= n - r; ++q)
{
for (std::size_t i = 0; i < 3; ++i)
{
auto pqr = md::submdspan(P, 0, pyr_idx(p, q, r) + (n + 1) * (n + 2) * (2 * n + 3) / 6 * ( i + 1 ),
md::full_extent);
for (std::size_t j = 0; j < pqr.size(); ++j)
pqr(j) *= std::sqrt(2 * (q + 0.5) * (p + 0.5)
* (std::max(p, q) + r + 1.5));
}
}
}
}

}
//-----------------------------------------------------------------------------
template <typename T>
Expand Down Expand Up @@ -3069,7 +3267,7 @@ int polyset::dim(cell::type celltype, polyset::type ptype, int d)
case cell::type::prism:
return (d + 1) * (d + 1) * (d + 2) / 2;
case cell::type::pyramid:
return (d + 1) * (d + 2) * (2 * d + 3) / 6;
return (d + 1) * (d + 2) * (2 * d + 3) / 6 * 4;
case cell::type::interval:
return (d + 1);
case cell::type::quadrilateral:
Expand Down
Loading