227 if constexpr (CELL::descriptor_t::d == 3) {
228 auto eps_minusY = getClampedEpsilon(cell.neighbor({0, -1, 0}));
229 auto eps_plusY = getClampedEpsilon(cell.neighbor({0, 1, 0}));
230 auto eps_minusX = getClampedEpsilon(cell.neighbor({-1, 0, 0}));
231 auto eps_plusX = getClampedEpsilon(cell.neighbor({1, 0, 0}));
232 auto eps_minusYminusX = getClampedEpsilon(cell.neighbor({-1, -1, 0}));
233 auto eps_minusYplusX = getClampedEpsilon(cell.neighbor({1, -1, 0}));
234 auto eps_plusYminusX = getClampedEpsilon(cell.neighbor({-1, 1, 0}));
235 auto eps_plusYplusX = getClampedEpsilon(cell.neighbor({1, 1, 0}));
236 auto eps_minusZ = getClampedEpsilon(cell.neighbor({0, 0, -1}));
237 auto eps_plusZ = getClampedEpsilon(cell.neighbor({0, 0, 1}));
238 auto eps_minusZminusY = getClampedEpsilon(cell.neighbor({0, -1, -1}));
239 auto eps_minusZplusY = getClampedEpsilon(cell.neighbor({0, 1, -1}));
240 auto eps_minusZminusX = getClampedEpsilon(cell.neighbor({-1, 0, -1}));
241 auto eps_minusZplusX = getClampedEpsilon(cell.neighbor({1, 0, -1}));
242 auto eps_plusZminusY = getClampedEpsilon(cell.neighbor({0, -1, 1}));
243 auto eps_plusZplusY = getClampedEpsilon(cell.neighbor({0, 1, 1}));
244 auto eps_plusZminusX = getClampedEpsilon(cell.neighbor({-1, 0, 1}));
245 auto eps_plusZplusX = getClampedEpsilon(cell.neighbor({1, 0, 1}));
246 auto eps_minusZminusYminusX = getClampedEpsilon(cell.neighbor({-1, -1, -1}));
247 auto eps_minusZplusYminusX = getClampedEpsilon(cell.neighbor({-1, 1, -1}));
248 auto eps_minusZminusYplusX = getClampedEpsilon(cell.neighbor({1, -1, -1}));
249 auto eps_minusZplusYplusX = getClampedEpsilon(cell.neighbor({1, 1, -1}));
250 auto eps_plusZminusYminusX = getClampedEpsilon(cell.neighbor({-1, -1, 1}));
251 auto eps_plusZplusYminusX = getClampedEpsilon(cell.neighbor({-1, 1, 1}));
252 auto eps_plusZminusYplusX = getClampedEpsilon(cell.neighbor({1, -1, 1}));
253 auto eps_plusZplusYplusX = getClampedEpsilon(cell.neighbor({1, 1, 1}));
256 normal[0] = V(4) * (eps_minusX - eps_plusX);
257 normal[0] += V(2) * ((eps_minusYminusX + eps_minusZminusX + eps_plusYminusX + eps_plusZminusX) - (eps_plusYplusX + eps_plusZplusX + eps_minusYplusX + eps_minusZplusX));
258 normal[0] += V(1) * ((eps_minusZminusYminusX + eps_plusZminusYminusX + eps_minusZplusYminusX + eps_plusZplusYminusX) - (eps_plusZplusYplusX + eps_minusZplusYplusX + eps_plusZminusYplusX + eps_minusZminusYplusX));
260 normal[1] = V(4) * (eps_minusY - eps_plusY);
261 normal[1] += V(2) * ((eps_minusYminusX + eps_minusZminusY + eps_minusYplusX + eps_plusZminusY) - (eps_plusYplusX + eps_plusZplusY + eps_plusYminusX + eps_minusZplusY));
262 normal[1] += V(1) * ((eps_minusZminusYminusX + eps_plusZminusYminusX + eps_plusZminusYplusX + eps_minusZminusYplusX) - (eps_plusZplusYplusX + eps_minusZplusYplusX + eps_minusZplusYminusX + eps_plusZplusYminusX));
264 normal[2] = V(4) * (eps_minusZ - eps_plusZ);
265 normal[2] += V(2) * ((eps_minusZminusX + eps_minusZminusY + eps_minusZplusX + eps_minusZplusY) - (eps_plusZplusX + eps_plusZplusY + eps_plusZminusX + eps_plusZminusY));
266 normal[2] += V(1) * ((eps_minusZminusYminusX + eps_minusZplusYplusX + eps_minusZplusYminusX + eps_minusZminusYplusX) - (eps_plusZplusYplusX + eps_plusZminusYminusX + eps_plusZminusYplusX + eps_plusZplusYminusX));
271 auto eps_minusY = getClampedEpsilon(cell.neighbor({0, -1}));
272 auto eps_plusY = getClampedEpsilon(cell.neighbor({0, 1}));
273 auto eps_minusX = getClampedEpsilon(cell.neighbor({-1, 0}));
274 auto eps_plusX = getClampedEpsilon(cell.neighbor({1, 0}));
275 auto eps_minusYminusX = getClampedEpsilon(cell.neighbor({-1, -1}));
276 auto eps_minusYplusX = getClampedEpsilon(cell.neighbor({1, -1}));
277 auto eps_plusYminusX = getClampedEpsilon(cell.neighbor({-1, 1}));
278 auto eps_plusYplusX = getClampedEpsilon(cell.neighbor({1, 1}));
281 normal[0] = V(2) * (eps_minusX - eps_plusX);
282 normal[0] += V(1) * ((eps_minusYminusX + eps_plusYminusX) - (eps_plusYplusX + eps_minusYplusX));
284 normal[1] = V(2) * (eps_minusY - eps_plusY);
285 normal[1] += V(1) * ((eps_minusYminusX + eps_minusYplusX) - (eps_plusYplusX + eps_plusYminusX));
324void rowPivotingLUSolver(std::array<T, N * N>& M, std::array<T, N>& x, std::array<T, N>& b,
const int Nsol) {
326 for (
int i = 0; i < Nsol; ++i) { M[i * N + i] += T(0); }
329 std::array<T, N * N> Prev_M = M;
332 std::array<int, N> row_perm{};
333 for (
int i = 0; i < N; ++i) { row_perm[i] = i; }
336 for (
int i = 0; i < Nsol; ++i) {
338 T maxValue = std::abs(M[i * N + i]);
340 for (
int j = i + 1; j < Nsol; ++j) {
341 T value = std::abs(M[j * N + i]);
342 if (value > maxValue) {
349 for (
int k = 0; k < Nsol; ++k) { std::swap(M[i * N + k], M[pivotRow * N + k]); }
350 std::swap(row_perm[i], row_perm[pivotRow]);
351 std::swap(b[i], b[pivotRow]);
354 for (
int j = i + 1; j < Nsol; ++j) {
355 M[j * N + i] /= M[i * N + i];
356 for (
int k = i + 1; k < Nsol; ++k) { M[j * N + k] -= M[j * N + i] * M[i * N + k]; }
361 for (
int i = 0; i < Nsol; ++i) { x[i] = b[i]; }
364 for (
int i = 0; i < Nsol; ++i) {
365 for (
int j = 0; j < i; ++j) { x[i] -= M[i * N + j] * x[j]; }
369 for (
int i = Nsol - 1; i >= 0; --i) {
370 for (
int j = i + 1; j < Nsol; ++j) { x[i] -= M[i * N + j] * x[j]; }
371 x[i] /= M[i * N + i];
375 std::array<T, N * N> tmp = Prev_M;
376 for (
int i = 0; i < Nsol; ++i) {
377 for (
int j = 0; j < Nsol; ++j) { Prev_M[i * N + j] = tmp[row_perm[i] * N + j]; }
379 iterativeRefinement<T, N>(Prev_M, M, x, b, Nsol);
383void completePivotingLUSolver(std::array<T, N * N>& M, std::array<T, N>& x, std::array<T, N>& b,
const int Nsol) {
385 for (
int i = 0; i < Nsol; ++i) { M[i * N + i] += T(0); }
388 std::array<int, N> row_perm{}, col_perm{};
389 for (
int i = 0; i < N; ++i) {
395 for (
int i = 0; i < Nsol; ++i) {
396 int pivotRow = i, pivotCol = i;
397 T maxValue = std::abs(M[i * N + i]);
399 for (
int r = i; r < Nsol; ++r) {
400 for (
int c = i; c < Nsol; ++c) {
401 T value = std::abs(M[r * N + c]);
402 if (value > maxValue) {
411 for (
int k = 0; k < Nsol; ++k) { std::swap(M[i * N + k], M[pivotRow * N + k]); }
412 std::swap(row_perm[i], row_perm[pivotRow]);
413 std::swap(b[i], b[pivotRow]);
417 for (
int k = 0; k < Nsol; ++k) { std::swap(M[k * N + i], M[k * N + pivotCol]); }
418 std::swap(col_perm[i], col_perm[pivotCol]);
421 for (
int j = i + 1; j < Nsol; ++j) {
422 M[j * N + i] /= M[i * N + i];
423 for (
int k = i + 1; k < Nsol; ++k) { M[j * N + k] -= M[j * N + i] * M[i * N + k]; }
428 for (
int i = 0; i < Nsol; ++i) { x[i] = b[i]; }
431 for (
int i = 0; i < Nsol; ++i) {
432 for (
int j = 0; j < i; ++j) { x[i] -= M[i * N + j] * x[j]; }
436 for (
int i = Nsol - 1; i >= 0; --i) {
437 for (
int j = i + 1; j < Nsol; ++j) { x[i] -= M[i * N + j] * x[j]; }
438 x[i] /= M[i * N + i];
443 std::array<T, N> tmp = x;
444 for (
int i = 0; i < Nsol; ++i) { x[col_perm[i]] = tmp[i]; }
448void columnPivotingQRSolver(std::array<T, N * N>& M, std::array<T, N>& x, std::array<T, N>& b,
const int Nsol) {
450 std::array<int, N> col_perm{};
451 for (
int i = 0; i < N; ++i) { col_perm[i] = i; }
454 std::array<T, N> col_norm{}, col_norm_tmp{};
455 for (
int i = 0; i < Nsol; ++i) {
457 for (
int j = 0; j < Nsol; ++j) {
norm += M[j * N + i] * M[j * N + i]; }
459 col_norm_tmp[i] = col_norm[i];
463 for (
int i = 0; i < Nsol; ++i) {
465 T maxValue = col_norm[i];
467 for (
int j = i + 1; j < Nsol; ++j) {
468 if (col_norm[j] > maxValue) {
469 maxValue = col_norm[j];
475 for (
int k = 0; k < Nsol; ++k) { std::swap(M[k * N + i], M[k * N + pivotCol]); }
476 std::swap(col_perm[i], col_perm[pivotCol]);
477 std::swap(col_norm[i], col_norm[pivotCol]);
478 std::swap(col_norm_tmp[i], col_norm_tmp[pivotCol]);
486 for (
int k = i; k < Nsol; ++k) {
norm += M[k * N + i] * M[k * N + i]; }
488 r = M[i * N + i] >= T(0) ? -
norm :
norm;
492 std::array<T, N> v{};
494 v[0] = M[i * N + i] - r;
495 for (
int k = i + 1; k < Nsol; ++k) { v[k - i] = M[k * N + i]; }
498 for (
int k = 0; k < Nsol - i; ++k) {
norm += v[k] * v[k]; }
503 for (
int k = 0; k < Nsol - i; ++k) { v[k] /=
norm; }
508 for (
int k = i; k < Nsol; ++k) {
509 T dot_product = T(0);
510 for (
int j = 0; j < Nsol - i; ++j) { dot_product += v[j] * M[(j + i) * N + k]; }
513 for (
int j = 0; j < Nsol - i; ++j) { M[(j + i) * N + k] -= v[j] * dot_product; }
518 T dot_product = T(0);
519 for (
int k = 0; k < Nsol - i; ++k) { dot_product += v[k] * b[k + i]; }
522 for (
int k = 0; k < Nsol - i; ++k) { b[k + i] -= v[k] * dot_product; }
526 for (
int k = i + 1; k < Nsol; ++k) {
527 T tmp = col_norm[k] * col_norm[k] - M[i * N + k] * M[i * N + k];
531 if (tmp <= T(0) ||
util::sqrt(tmp) < T(0.1) * col_norm_tmp[k]) {
533 for (
int j = i + 1; j < Nsol; ++j) {
norm += M[j * N + k] * M[j * N + k]; }
535 col_norm_tmp[k] = col_norm[k];
544 for (
int k = i + 1; k < Nsol; ++k) { M[k * N + i] = T(0); }
548 for (
int i = Nsol - 1; i >= 0; --i) {
550 for (
int j = i + 1; j < Nsol; ++j) { sum += M[i * N + j] * x[j]; }
551 x[i] = (b[i] - sum) / M[i * N + i];
556 std::array<T, N> tmp = x;
557 for (
int i = 0; i < Nsol; ++i) { x[col_perm[i]] = tmp[i]; }
644V computeCurvaturePLIC2D(CELL& cell) {
645 using DESCRIPTOR =
typename CELL::descriptor_t;
649 const auto normal = computeInterfaceNormal(cell);
658 std::uint8_t nbrInterfaces = std::uint8_t(0);
661 const V centerOffset = plicCube<V>(getClampedEpsilon(cell), by);
664 std::array<Vector<V, DESCRIPTOR::d>, 6> points;
666 for (
int iPop = 1; iPop < DESCRIPTOR::q; ++iPop) {
676 const Vector<V, 3> ei = {V(direction[0]), V(direction[1]), V(0)};
677 const V offset = plicCube<V>(getClampedEpsilon(nbrCell), by) - centerOffset;
684 std::array<V, 4> M{};
685 std::array<V, 2> solution{};
686 std::array<V, 2> b{};
688 for (std::uint8_t i = 0; i < nbrInterfaces; ++i) {
689 const V x = points[i][0];
690 const V y = points[i][1];
707 if (nbrInterfaces >= 2) {
708 rowPivotingLUSolver<V, 2>(M, solution, b, 2);
710 rowPivotingLUSolver<V, 2>(M, solution, b,
util::min(2, nbrInterfaces));
714 if (nbrInterfaces >= 2) {
715 completePivotingLUSolver<V, 2>(M, solution, b, 2);
717 completePivotingLUSolver<V, 2>(M, solution, b,
util::min(2, nbrInterfaces));
721 if (nbrInterfaces >= 2) {
722 columnPivotingQRSolver<V, 2>(M, solution, b, 2);
724 columnPivotingQRSolver<V, 2>(M, solution, b,
util::min(2, nbrInterfaces));
729 if (nbrInterfaces >= 2) {
730 completePivotingLUSolver<V, 2>(M, solution, b, 2);
732 completePivotingLUSolver<V, 2>(M, solution, b,
util::min(2, nbrInterfaces));
736 const V A = solution[0], H = solution[1];
743V computeCurvaturePLIC3D(CELL& cell) {
744 using DESCRIPTOR =
typename CELL::descriptor_t;
748 auto bz = computeInterfaceNormal(cell);
761 std::uint8_t nbrInterfaces = std::uint8_t(0);
764 const V centerOffset = plicCube<V>(getClampedEpsilon(cell), bz);
767 std::array<Vector<V, DESCRIPTOR::d>, 24> points;
769 for (
int iPop = 1; iPop < DESCRIPTOR::q; ++iPop) {
780 const V offset = plicCube<V>(getClampedEpsilon(nbrCell), bz) - centerOffset;
787 std::array<V, 25> M{};
788 std::array<V, 5> solution{};
789 std::array<V, 5> b{};
791 for (std::uint8_t i = 0; i < nbrInterfaces; ++i) {
792 const V x = points[i][0];
793 const V y = points[i][1];
794 const V z = points[i][2];
824 for (std::uint8_t i = 1; i < 5; ++i) {
825 for (std::uint8_t j = 0; j < i; ++j) {
826 M[i * 5 + j] = M[j * 5 + i];
832 if (nbrInterfaces >= 5) {
833 rowPivotingLUSolver<V, 5>(M, solution, b, 5);
835 rowPivotingLUSolver<V, 5>(M, solution, b,
util::min(5, nbrInterfaces));
839 if (nbrInterfaces >= 5) {
840 completePivotingLUSolver<V, 5>(M, solution, b, 5);
842 completePivotingLUSolver<V, 5>(M, solution, b,
util::min(5, nbrInterfaces));
846 if (nbrInterfaces >= 5) {
847 columnPivotingQRSolver<V, 5>(M, solution, b, 5);
849 columnPivotingQRSolver<V, 5>(M, solution, b,
util::min(5, nbrInterfaces));
854 if (nbrInterfaces >= 5) {
855 completePivotingLUSolver<V, 5>(M, solution, b, 5);
857 completePivotingLUSolver<V, 5>(M, solution, b,
util::min(5, nbrInterfaces));
861 const V A = solution[0], B = solution[1], C = solution[2], H = solution[3], I = solution[4];
862 const V curvature = (A * (I * I + V(1)) + B * (H * H + V(1)) - C * H * I) *
util::cube(V(1) /
util::sqrt(H * H + I * I + V(1)));
867V computeCurvatureFDM3D(CELL& cell) {
868 using DESCRIPTOR =
typename CELL::descriptor_t;
870 const auto normal = computeInterfaceNormal(cell);
873 const std::uint32_t gaussianMultipliers [DESCRIPTOR::q] =
876 std::uint32_t(4), std::uint32_t(4), std::uint32_t(4),
877 std::uint32_t(2), std::uint32_t(2), std::uint32_t(2),
878 std::uint32_t(2), std::uint32_t(2), std::uint32_t(2),
879 std::uint32_t(1), std::uint32_t(1), std::uint32_t(1), std::uint32_t(1),
880 std::uint32_t(4), std::uint32_t(4), std::uint32_t(4),
881 std::uint32_t(2), std::uint32_t(2), std::uint32_t(2),
882 std::uint32_t(2), std::uint32_t(2), std::uint32_t(2),
883 std::uint32_t(1), std::uint32_t(1), std::uint32_t(1), std::uint32_t(1)
889 for (
int iPop = 1; iPop < DESCRIPTOR::q; ++iPop) {
891 auto nbrCell = cell.neighbor(direction);
899 const auto nbrNormal =
util::normalize(computeInterfaceNormal(nbrCell));
900 const V weight = gaussianMultipliers[iPop];
905 curvature /= weightSum;