fix(equation-and-linear-solve): address review findings
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
@@ -158,6 +159,78 @@ fesa::Domain build_parallel_domain(
|
||||
return finish_domain(std::move(builder), {"Load", {}, {}});
|
||||
}
|
||||
|
||||
fesa::Domain build_rounding_domain(const bool large_element_first) {
|
||||
fesa::DomainBuilder builder;
|
||||
builder.add_node({
|
||||
fesa::NodeId{4},
|
||||
fesa::EntityOrigin{"BeamPart", "Beam-1", 1},
|
||||
fesa::Vec3{0.0, 0.0, 0.0},
|
||||
});
|
||||
builder.add_node({
|
||||
fesa::NodeId{10},
|
||||
fesa::EntityOrigin{"BeamPart", "Beam-1", 2},
|
||||
fesa::Vec3{1.0, 0.0, 0.0},
|
||||
});
|
||||
|
||||
for (std::size_t index = 0; index < 3; ++index) {
|
||||
fesa::IsotropicElastic material = unit_material();
|
||||
material.id =
|
||||
fesa::MaterialId{static_cast<std::int64_t>(index)};
|
||||
material.name = "Material-" + std::to_string(index);
|
||||
material.young = index == 2 ? 1.0e16 : 1.0;
|
||||
builder.add_material(std::move(material));
|
||||
}
|
||||
builder.add_section(unit_section());
|
||||
|
||||
std::array<std::size_t, 3> storage_order{0, 1, 2};
|
||||
if (large_element_first) {
|
||||
storage_order = {2, 0, 1};
|
||||
}
|
||||
for (const std::size_t index : storage_order) {
|
||||
builder.add_beam_element({
|
||||
fesa::ElementId{static_cast<std::int64_t>(index)},
|
||||
fesa::EntityOrigin{
|
||||
"BeamPart",
|
||||
"Beam-1",
|
||||
static_cast<std::int64_t>((index + 1) * 10),
|
||||
},
|
||||
{fesa::NodeId{4}, fesa::NodeId{10}},
|
||||
fesa::MaterialId{static_cast<std::int64_t>(index)},
|
||||
fesa::SectionId{0},
|
||||
});
|
||||
}
|
||||
return finish_domain(std::move(builder), {"Load", {}, {}});
|
||||
}
|
||||
|
||||
fesa::Domain build_orphan_node_domain() {
|
||||
fesa::DomainBuilder builder;
|
||||
builder.add_node({
|
||||
fesa::NodeId{0},
|
||||
fesa::EntityOrigin{"BeamPart", "Beam-1", 1},
|
||||
fesa::Vec3{0.0, 0.0, 0.0},
|
||||
});
|
||||
builder.add_node({
|
||||
fesa::NodeId{1},
|
||||
fesa::EntityOrigin{"BeamPart", "Beam-1", 2},
|
||||
fesa::Vec3{1.0, 0.0, 0.0},
|
||||
});
|
||||
builder.add_node({
|
||||
fesa::NodeId{2},
|
||||
fesa::EntityOrigin{"BeamPart", "Beam-1", 3},
|
||||
fesa::Vec3{2.0, 0.0, 0.0},
|
||||
});
|
||||
builder.add_material(unit_material());
|
||||
builder.add_section(unit_section());
|
||||
builder.add_beam_element({
|
||||
fesa::ElementId{0},
|
||||
fesa::EntityOrigin{"BeamPart", "Beam-1", 1},
|
||||
{fesa::NodeId{0}, fesa::NodeId{1}},
|
||||
fesa::MaterialId{0},
|
||||
fesa::SectionId{0},
|
||||
});
|
||||
return finish_domain(std::move(builder), {"Load", {}, {}});
|
||||
}
|
||||
|
||||
double csr_value(
|
||||
const fesa::SymmetricCsr& matrix,
|
||||
std::size_t row,
|
||||
@@ -246,6 +319,29 @@ TEST(SymmetricCsr, StoresSortedUpperTriangleWithValidOffsets) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SparsePattern, IncludesZeroDiagonalForEveryOrphanNodeDof) {
|
||||
const fesa::Domain domain = build_orphan_node_domain();
|
||||
const fesa::SymmetricCsr matrix =
|
||||
fesa::assemble_serial(
|
||||
domain, fesa::DofManager::build(domain))
|
||||
.stiffness;
|
||||
|
||||
ASSERT_EQ(matrix.order, 18);
|
||||
for (std::size_t row = 0; row < matrix.order; ++row) {
|
||||
const auto begin =
|
||||
matrix.column_indices.begin() + matrix.row_offsets[row];
|
||||
const auto end =
|
||||
matrix.column_indices.begin() + matrix.row_offsets[row + 1];
|
||||
const auto diagonal = std::lower_bound(
|
||||
begin, end, static_cast<std::int32_t>(row));
|
||||
ASSERT_NE(diagonal, end);
|
||||
EXPECT_EQ(*diagonal, static_cast<std::int32_t>(row));
|
||||
}
|
||||
for (std::size_t row = 12; row < 18; ++row) {
|
||||
EXPECT_DOUBLE_EQ(csr_value(matrix, row, row), 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SerialAssembly, AssemblesHandCalculatedAxialChainAndFullLoad) {
|
||||
const fesa::Domain domain = build_chain_domain(false);
|
||||
const fesa::DofManager dofs = fesa::DofManager::build(domain);
|
||||
@@ -307,6 +403,36 @@ TEST(SerialAssembly, MergesDuplicateElementContributions) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SerialAssembly, ReducesByElementOriginNotDomainStorageOrder) {
|
||||
const fesa::Domain origin_order_domain =
|
||||
build_rounding_domain(false);
|
||||
const fesa::Domain storage_order_domain =
|
||||
build_rounding_domain(true);
|
||||
|
||||
const double origin_order_value = csr_value(
|
||||
fesa::assemble_serial(
|
||||
origin_order_domain,
|
||||
fesa::DofManager::build(origin_order_domain))
|
||||
.stiffness,
|
||||
0,
|
||||
0);
|
||||
const double storage_order_value = csr_value(
|
||||
fesa::assemble_serial(
|
||||
storage_order_domain,
|
||||
fesa::DofManager::build(storage_order_domain))
|
||||
.stiffness,
|
||||
0,
|
||||
0);
|
||||
const double expected = (1.0 + 1.0) + 1.0e16;
|
||||
|
||||
EXPECT_EQ(
|
||||
std::bit_cast<std::uint64_t>(origin_order_value),
|
||||
std::bit_cast<std::uint64_t>(expected));
|
||||
EXPECT_EQ(
|
||||
std::bit_cast<std::uint64_t>(storage_order_value),
|
||||
std::bit_cast<std::uint64_t>(expected));
|
||||
}
|
||||
|
||||
TEST(SerialAssembly, IsIndependentOfDomainStorageAndExternalLabelOrder) {
|
||||
const fesa::Domain first_domain = build_chain_domain(false);
|
||||
const fesa::Domain second_domain = build_chain_domain(true);
|
||||
|
||||
Reference in New Issue
Block a user