feat(deterministic-parallel-assembly): step 0 — canonical-contribution-order
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#include <fesa/assembly/contribution.hpp>
|
||||
#include <fesa/assembly/serial_assembler.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -187,8 +188,9 @@ fesa::Domain build_rounding_domain(const bool large_element_first) {
|
||||
storage_order = {2, 0, 1};
|
||||
}
|
||||
for (const std::size_t index : storage_order) {
|
||||
constexpr std::array<std::int64_t, 3> element_ids{1, 2, 0};
|
||||
builder.add_beam_element({
|
||||
fesa::ElementId{static_cast<std::int64_t>(index)},
|
||||
fesa::ElementId{element_ids[index]},
|
||||
fesa::EntityOrigin{
|
||||
"BeamPart",
|
||||
"Beam-1",
|
||||
@@ -250,6 +252,80 @@ double csr_value(
|
||||
std::distance(matrix.column_indices.begin(), found))];
|
||||
}
|
||||
|
||||
std::vector<std::uint64_t> value_bits(
|
||||
const fesa::SymmetricCsr& matrix) {
|
||||
std::vector<std::uint64_t> bits;
|
||||
bits.reserve(matrix.values.size());
|
||||
for (const double value : matrix.values) {
|
||||
bits.push_back(std::bit_cast<std::uint64_t>(value));
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
TEST(CanonicalContribution, OrdersByCoordinateElementAndLocalOrder) {
|
||||
const std::vector<fesa::MatrixContribution> contributions{
|
||||
{1, 2, fesa::ElementId{9}, 4, 9.0},
|
||||
{0, 2, fesa::ElementId{3}, 8, 3.8},
|
||||
{0, 2, fesa::ElementId{3}, 2, 3.2},
|
||||
{0, 2, fesa::ElementId{1}, 7, 1.7},
|
||||
{0, 0, fesa::ElementId{5}, 0, 5.0},
|
||||
};
|
||||
|
||||
const std::vector<fesa::MatrixContribution> canonical =
|
||||
fesa::canonicalize_contributions(contributions);
|
||||
|
||||
ASSERT_EQ(canonical.size(), contributions.size());
|
||||
EXPECT_EQ(canonical[0].row, 0);
|
||||
EXPECT_EQ(canonical[0].column, 0);
|
||||
EXPECT_EQ(canonical[0].element, fesa::ElementId{5});
|
||||
EXPECT_EQ(canonical[1].element, fesa::ElementId{1});
|
||||
EXPECT_EQ(canonical[2].element, fesa::ElementId{3});
|
||||
EXPECT_EQ(canonical[2].local_order, 2);
|
||||
EXPECT_EQ(canonical[3].element, fesa::ElementId{3});
|
||||
EXPECT_EQ(canonical[3].local_order, 8);
|
||||
EXPECT_EQ(canonical[4].row, 1);
|
||||
EXPECT_EQ(canonical[4].column, 2);
|
||||
}
|
||||
|
||||
TEST(DeterministicMerge, IsBitwiseStableAcrossInputPermutations) {
|
||||
const std::vector<fesa::MatrixContribution> contributions{
|
||||
{0, 1, fesa::ElementId{2}, 0, 1.0},
|
||||
{0, 1, fesa::ElementId{0}, 0, 1.0e16},
|
||||
{0, 1, fesa::ElementId{1}, 0, -1.0e16},
|
||||
{1, 1, fesa::ElementId{1}, 1, -0.0},
|
||||
{1, 1, fesa::ElementId{0}, 1, +0.0},
|
||||
};
|
||||
const std::vector<fesa::MatrixContribution> canonical =
|
||||
fesa::canonicalize_contributions(contributions);
|
||||
const fesa::SymmetricCsr expected =
|
||||
fesa::merge_contributions(2, canonical);
|
||||
|
||||
std::array<std::size_t, 5> permutation{0, 1, 2, 3, 4};
|
||||
do {
|
||||
std::vector<fesa::MatrixContribution> shuffled;
|
||||
shuffled.reserve(contributions.size());
|
||||
for (const std::size_t index : permutation) {
|
||||
shuffled.push_back(contributions[index]);
|
||||
}
|
||||
const std::vector<fesa::MatrixContribution> shuffled_canonical =
|
||||
fesa::canonicalize_contributions(shuffled);
|
||||
const fesa::SymmetricCsr actual =
|
||||
fesa::merge_contributions(2, shuffled_canonical);
|
||||
|
||||
EXPECT_EQ(actual.order, expected.order);
|
||||
EXPECT_EQ(actual.row_offsets, expected.row_offsets);
|
||||
EXPECT_EQ(actual.column_indices, expected.column_indices);
|
||||
EXPECT_EQ(value_bits(actual), value_bits(expected));
|
||||
} while (std::ranges::next_permutation(permutation).found);
|
||||
|
||||
EXPECT_EQ(
|
||||
std::bit_cast<std::uint64_t>(csr_value(expected, 0, 1)),
|
||||
std::bit_cast<std::uint64_t>(1.0));
|
||||
EXPECT_EQ(
|
||||
std::bit_cast<std::uint64_t>(csr_value(expected, 1, 1)),
|
||||
std::bit_cast<std::uint64_t>(+0.0));
|
||||
}
|
||||
|
||||
TEST(SparsePattern, BuildsExpectedTwoElementChainStructure) {
|
||||
const fesa::Domain domain = build_chain_domain(false);
|
||||
const fesa::DofManager dofs = fesa::DofManager::build(domain);
|
||||
|
||||
Reference in New Issue
Block a user