feat(cpp-object-oriented-modular-refactoring): step 16 - generic-sparse-assembler
This commit is contained in:
@@ -6,11 +6,13 @@
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "fesa/analysis/analysis_model.h"
|
||||
#include "fesa/assembly/parallel_for.h"
|
||||
#include "fesa/elements/element.h"
|
||||
#include "fesa/elements/mitc4_shell.h"
|
||||
#include "fesa/fem/dof_manager.h"
|
||||
#include "fesa/model/domain.h"
|
||||
@@ -180,6 +182,42 @@ class ReverseParallelFor final : public fesa::ParallelFor {
|
||||
mutable std::size_t observed_count_{0U};
|
||||
};
|
||||
|
||||
class FakeStiffnessElement final : public fesa::Element {
|
||||
public:
|
||||
FakeStiffnessElement(fesa::ElementDofLayout layout, fesa::Matrix stiffness)
|
||||
: layout_{std::move(layout)}, stiffness_{std::move(stiffness)} {}
|
||||
|
||||
const fesa::ElementDofLayout& DofLayout() const noexcept override {
|
||||
return layout_;
|
||||
}
|
||||
|
||||
fesa::Result<fesa::ElementStiffnessContribution> ComputeStiffness()
|
||||
const override {
|
||||
return fesa::Result<fesa::ElementStiffnessContribution>::Success(
|
||||
{layout_, stiffness_});
|
||||
}
|
||||
|
||||
fesa::Result<fesa::ElementResultBundle> Recover(
|
||||
const fesa::Vector&) const override {
|
||||
return fesa::Result<fesa::ElementResultBundle>::Success(
|
||||
{layout_.source_id, fesa::BeamElementResultRows{}});
|
||||
}
|
||||
|
||||
private:
|
||||
fesa::ElementDofLayout layout_;
|
||||
fesa::Matrix stiffness_;
|
||||
};
|
||||
|
||||
fesa::Matrix MatrixFromRows(const std::vector<std::vector<double>>& rows) {
|
||||
fesa::Matrix matrix{rows.size(), rows.empty() ? 0U : rows.front().size()};
|
||||
for (std::size_t row = 0U; row < rows.size(); ++row) {
|
||||
for (std::size_t column = 0U; column < rows[row].size(); ++column) {
|
||||
matrix(row, column) = rows[row][column];
|
||||
}
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void ExpectByteIdentical(const fesa::SparseMatrix& actual,
|
||||
const fesa::SparseMatrix& expected) {
|
||||
EXPECT_TRUE(ByteIdentical(actual.RowOffsets(), expected.RowOffsets()));
|
||||
@@ -187,6 +225,66 @@ void ExpectByteIdentical(const fesa::SparseMatrix& actual,
|
||||
EXPECT_TRUE(ByteIdentical(actual.Values(), expected.Values()));
|
||||
}
|
||||
|
||||
// C-ASSEMBLY-001
|
||||
TEST(SparseAssembly,
|
||||
AssemblesFakeRuntimeContributionsIntoExactDeterministicCsr) {
|
||||
auto domain = fesa::Domain::Create(MakeDefinition());
|
||||
ASSERT_TRUE(domain.HasValue());
|
||||
auto model = fesa::AnalysisModel::Create(domain.Value());
|
||||
ASSERT_TRUE(model.HasValue());
|
||||
|
||||
fesa::ElementDofLayout first_layout{
|
||||
{"Beam-1", 10, "10"}, {0U, 2U}, {fesa::DofComponent::kUx}};
|
||||
FakeStiffnessElement first{std::move(first_layout),
|
||||
MatrixFromRows({{1.0, 2.0}, {3.0, 4.0}})};
|
||||
fesa::ElementDofLayout second_layout{
|
||||
{"Beam-1", 20, "20"},
|
||||
{2U},
|
||||
{fesa::DofComponent::kUx, fesa::DofComponent::kUz,
|
||||
fesa::DofComponent::kUrz}};
|
||||
FakeStiffnessElement second{
|
||||
std::move(second_layout),
|
||||
MatrixFromRows({{5.0, 6.0, 7.0}, {8.0, 9.0, 10.0}, {11.0, 12.0, 13.0}})};
|
||||
const fesa::ElementView elements{std::cref(first), std::cref(second)};
|
||||
fesa::DofManager dofs;
|
||||
ASSERT_TRUE(dofs.Build(model.Value(), elements).IsOk());
|
||||
|
||||
fesa::SerialParallelFor serial_executor;
|
||||
fesa::TbbParallelFor tbb_executor;
|
||||
ReverseParallelFor reverse_executor;
|
||||
auto serial =
|
||||
fesa::SparseAssembler::Assemble(elements, dofs, serial_executor);
|
||||
auto tbb = fesa::SparseAssembler::Assemble(elements, dofs, tbb_executor);
|
||||
auto reversed =
|
||||
fesa::SparseAssembler::Assemble(elements, dofs, reverse_executor);
|
||||
ASSERT_TRUE(serial.HasValue());
|
||||
ASSERT_TRUE(tbb.HasValue());
|
||||
ASSERT_TRUE(reversed.HasValue());
|
||||
|
||||
EXPECT_EQ(reverse_executor.Calls(), 1U);
|
||||
EXPECT_EQ(reverse_executor.ObservedCount(), elements.size());
|
||||
EXPECT_EQ(serial.Value().Rows(), 18U);
|
||||
EXPECT_EQ(serial.Value().Columns(), 18U);
|
||||
EXPECT_EQ(serial.Value().RowOffsets(),
|
||||
(std::vector<std::size_t>{0U, 2U, 2U, 2U, 2U, 2U, 2U, 2U, 2U, 2U,
|
||||
2U, 2U, 2U, 6U, 6U, 9U, 9U, 9U, 12U}));
|
||||
EXPECT_EQ(serial.Value().ColumnIndices(),
|
||||
(std::vector<std::size_t>{0U, 12U, 0U, 12U, 14U, 17U, 12U, 14U, 17U,
|
||||
12U, 14U, 17U}));
|
||||
EXPECT_EQ(serial.Value().Values(),
|
||||
(std::vector<double>{1.0, 2.0, 3.0, 9.0, 6.0, 7.0, 8.0, 9.0, 10.0,
|
||||
11.0, 12.0, 13.0}));
|
||||
ExpectByteIdentical(tbb.Value(), serial.Value());
|
||||
ExpectByteIdentical(reversed.Value(), serial.Value());
|
||||
|
||||
for (std::size_t repetition = 0U; repetition < 8U; ++repetition) {
|
||||
auto repeated =
|
||||
fesa::SparseAssembler::Assemble(elements, dofs, tbb_executor);
|
||||
ASSERT_TRUE(repeated.HasValue());
|
||||
ExpectByteIdentical(repeated.Value(), serial.Value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SparseAssembly, SerialTbbAndRepeatedRunsAreByteIdentical) {
|
||||
auto domain_result = fesa::Domain::Create(MakeDefinition());
|
||||
ASSERT_TRUE(domain_result.HasValue());
|
||||
|
||||
Reference in New Issue
Block a user