Files
FESADev/tests/reference/mitc4_reference_cases_test.cpp
T

195 lines
7.1 KiB
C++

#include "mitc4_reference_comparison.hpp"
#include "fesa/app/fesa_application.hpp"
#include <gtest/gtest.h>
#include <algorithm>
#include <cstddef>
#include <filesystem>
#include <fstream>
#include <iterator>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#ifndef FESA_TEST_SOURCE_DIR
#error FESA_TEST_SOURCE_DIR must identify the repository root.
#endif
#ifndef FESA_TEST_BINARY_DIR
#error FESA_TEST_BINARY_DIR must identify the CMake binary root.
#endif
namespace {
constexpr const char* kInternalFormulation = "FESA-MITC4";
constexpr const char* kIntegrationRule =
"2x2x2-gauss; mitc4-edge-midpoint-shear";
constexpr std::size_t kNodeCount = 49U;
constexpr std::size_t kComponentCount = 6U;
std::string readBytes(const std::filesystem::path& path) {
std::ifstream stream{path, std::ios::binary};
if (!stream) {
throw std::runtime_error{"Unable to read declared reference artifact."};
}
return {std::istreambuf_iterator<char>{stream},
std::istreambuf_iterator<char>{}};
}
struct ArtifactSnapshot {
std::string bytes;
std::filesystem::file_time_type lastWriteTime;
};
ArtifactSnapshot snapshot(const std::filesystem::path& path) {
return {readBytes(path), std::filesystem::last_write_time(path)};
}
void expectUnchanged(
const std::filesystem::path& path, const ArtifactSnapshot& before) {
EXPECT_EQ(readBytes(path), before.bytes) << path.string();
EXPECT_EQ(std::filesystem::last_write_time(path), before.lastWriteTime)
<< path.string();
}
struct CaseEvidence {
fesa::test::Mitc4ComparisonReport report;
std::filesystem::path comparisonJson;
};
CaseEvidence runCase(
const std::string& caseId,
const std::string& sourceElementType,
const std::filesystem::path& referenceDirectory,
const std::filesystem::path& input,
const std::filesystem::path& csv,
const std::string& outputName) {
const auto inputBefore = snapshot(input);
const auto csvBefore = snapshot(csv);
const std::filesystem::path outputDirectory =
std::filesystem::path{FESA_TEST_BINARY_DIR} / "reference" / outputName;
std::error_code error;
std::filesystem::remove_all(outputDirectory, error);
error.clear();
if (!std::filesystem::create_directories(outputDirectory, error) || error) {
throw std::runtime_error{"Unable to create MITC4 evidence directory."};
}
const auto results = outputDirectory / "results.h5";
const auto comparison = outputDirectory / "comparison.json";
fesa::FesaApplication application;
EXPECT_EQ(
application.run({input.string(), "--output", results.string()}), 0);
EXPECT_TRUE(std::filesystem::is_regular_file(results));
auto comparisonResult = fesa::test::Mitc4ReferenceComparison::compare(
{caseId, sourceElementType, input, csv, results});
if (!comparisonResult.hasValue()) {
ADD_FAILURE() << "MITC4 comparison precheck failed for " << caseId;
return {{}, comparison};
}
EXPECT_TRUE(
fesa::test::Mitc4ReferenceComparison::writeDeterministicJson(
comparisonResult.value(), comparison)
.isOk());
EXPECT_TRUE(std::filesystem::is_regular_file(comparison));
std::vector<std::string> generated;
for (const auto& entry :
std::filesystem::directory_iterator{outputDirectory}) {
generated.push_back(entry.path().filename().string());
}
std::sort(generated.begin(), generated.end());
EXPECT_EQ(
generated,
(std::vector<std::string>{"comparison.json", "results.h5"}));
EXPECT_TRUE(std::filesystem::is_directory(referenceDirectory));
expectUnchanged(input, inputBefore);
expectUnchanged(csv, csvBefore);
return {std::move(comparisonResult.value()), comparison};
}
void expectCommonMetadata(
const fesa::test::Mitc4ComparisonReport& report,
const std::string& caseId,
const std::string& sourceElementType) {
EXPECT_EQ(report.caseId, caseId);
EXPECT_EQ(report.sourceElementType, sourceElementType);
EXPECT_EQ(report.internalFormulation, kInternalFormulation);
EXPECT_EQ(report.integrationRule, kIntegrationRule);
}
void expectComparisonCoverage(
const fesa::test::Mitc4ComparisonReport& report) {
ASSERT_EQ(report.rows.size(), kNodeCount * kComponentCount);
ASSERT_EQ(report.metrics.size(), kComponentCount);
ASSERT_EQ(report.vectorMetrics.size(), kNodeCount);
EXPECT_TRUE(report.passed);
const std::size_t blockingRows = static_cast<std::size_t>(std::count_if(
report.rows.begin(), report.rows.end(),
[](const fesa::test::Mitc4RowDecision& row) {
return row.blocking;
}));
const std::size_t rotationRows = report.rows.size() - blockingRows;
EXPECT_EQ(blockingRows, kNodeCount * 3U);
EXPECT_EQ(rotationRows, kNodeCount * 3U);
EXPECT_TRUE(std::all_of(
report.rows.begin(), report.rows.end(),
[](const fesa::test::Mitc4RowDecision& row) {
return !row.blocking || row.withinTolerance;
}));
EXPECT_EQ(
report.warnings.size(),
static_cast<std::size_t>(std::count_if(
report.rows.begin(), report.rows.end(),
[](const fesa::test::Mitc4RowDecision& row) {
return !row.blocking && !row.withinTolerance;
})));
}
// MITC4-E2E-S4-001
TEST(Mitc4S4Reference, PreservesS4AndWritesCommonMitc4Metadata) {
const std::filesystem::path root{FESA_TEST_SOURCE_DIR};
const auto directory = root / "reference" / "shell";
const auto evidence = runCase(
"shell-s4", "S4", directory, directory / "shell.inp",
directory / "shell displacements.csv", "mitc4-shell-s4-metadata");
expectCommonMetadata(evidence.report, "shell-s4", "S4");
}
// MITC4-E2E-S4-002
TEST(Mitc4S4Reference, PassesBlockingUAndReportsEveryUrRow) {
const std::filesystem::path root{FESA_TEST_SOURCE_DIR};
const auto directory = root / "reference" / "shell";
const auto evidence = runCase(
"shell-s4", "S4", directory, directory / "shell.inp",
directory / "shell displacements.csv", "mitc4-shell-s4-comparison");
expectCommonMetadata(evidence.report, "shell-s4", "S4");
expectComparisonCoverage(evidence.report);
}
// MITC4-E2E-S4R-001
TEST(Mitc4S4RReference, PreservesS4RAndWritesCommonMitc4Metadata) {
const std::filesystem::path root{FESA_TEST_SOURCE_DIR};
const auto directory = root / "reference" / "shellR";
const auto evidence = runCase(
"shell-s4r", "S4R", directory, directory / "shellR.inp",
directory / "shellR displacements.csv", "mitc4-shell-s4r-metadata");
expectCommonMetadata(evidence.report, "shell-s4r", "S4R");
}
// MITC4-E2E-S4R-002
TEST(Mitc4S4RReference, PassesBlockingUAndReportsEveryUrRow) {
const std::filesystem::path root{FESA_TEST_SOURCE_DIR};
const auto directory = root / "reference" / "shellR";
const auto evidence = runCase(
"shell-s4r", "S4R", directory, directory / "shellR.inp",
directory / "shellR displacements.csv", "mitc4-shell-s4r-comparison");
expectCommonMetadata(evidence.report, "shell-s4r", "S4R");
expectComparisonCoverage(evidence.report);
}
} // namespace