#include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr std::size_t benchmark_element_count = 1000; fesa::Domain build_beam_chain() { fesa::DomainBuilder builder; for (std::size_t index = 0; index <= benchmark_element_count; ++index) { builder.add_node({ fesa::NodeId{static_cast(index)}, fesa::EntityOrigin{ "BenchmarkPart", "Benchmark-1", static_cast(index + 1), }, fesa::Vec3{static_cast(index), 0.0, 0.0}, }); } builder.add_material({ fesa::MaterialId{0}, "Steel", 210.0e9, 0.3, }); builder.add_section({ fesa::SectionId{0}, "General", 0.02, 3.0e-5, 4.0e-5, 2.0e-5, 0.015, 0.016, fesa::ShearPropertySource::input, fesa::Vec3{0.0, 1.0, 0.0}, {}, }); for (std::size_t index = 0; index < benchmark_element_count; ++index) { builder.add_beam_element({ fesa::ElementId{static_cast(index)}, fesa::EntityOrigin{ "BenchmarkPart", "Benchmark-1", static_cast(index + 1), }, { fesa::NodeId{static_cast(index)}, fesa::NodeId{static_cast(index + 1)}, }, fesa::MaterialId{0}, fesa::SectionId{0}, }); } builder.set_step({"Benchmark", {}, {}}); auto result = std::move(builder).build(); if (!result.domain.has_value()) { throw std::runtime_error{"Benchmark Domain failed validation."}; } return std::move(*result.domain); } template std::pair measure(Operation&& operation) { const auto start = std::chrono::steady_clock::now(); fesa::EquationSystem result = std::forward(operation)(); const auto finish = std::chrono::steady_clock::now(); const double milliseconds = std::chrono::duration(finish - start).count(); return {std::move(result), milliseconds}; } std::vector bits(const std::vector& values) { std::vector result; result.reserve(values.size()); for (const double value : values) { result.push_back(std::bit_cast(value)); } return result; } bool same_system( const fesa::EquationSystem& left, const fesa::EquationSystem& right) { return left.stiffness.order == right.stiffness.order && left.stiffness.row_offsets == right.stiffness.row_offsets && left.stiffness.column_indices == right.stiffness.column_indices && bits(left.stiffness.values) == bits(right.stiffness.values) && bits(left.force) == bits(right.force); } std::size_t available_concurrency() { const std::size_t available = static_cast(std::thread::hardware_concurrency()); return available == 0 ? 1 : available; } } // namespace int main() { try { const fesa::Domain domain = build_beam_chain(); const fesa::DofManager dofs = fesa::DofManager::build(domain); const std::size_t threads = available_concurrency(); auto [serial, serial_ms] = measure( [&] { return fesa::assemble_serial(domain, dofs); }); auto [parallel, parallel_ms] = measure([&] { return fesa::assemble_parallel(domain, dofs, {threads, 1}); }); if (!same_system(serial, parallel)) { std::cerr << "Serial and parallel assembly results differ.\n"; return 1; } std::cout << "elements=" << domain.beam_elements().size() << " serial_ms=" << serial_ms << " parallel_ms=" << parallel_ms << " parallel_threads=" << threads << '\n'; return 0; } catch (const std::exception& error) { std::cerr << "Assembly benchmark failed: " << error.what() << '\n'; return 1; } }