refactor: extract results reference comparison

This commit is contained in:
NINI
2026-05-05 01:38:04 +09:00
parent 339bf1cbb9
commit 421ad5a707
9 changed files with 469 additions and 257 deletions
+120
View File
@@ -0,0 +1,120 @@
#include "fesa/Results/Results.hpp"
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
namespace {
void check(bool value, const char* message) {
if (!value) {
throw std::runtime_error(message);
}
}
std::string sourceRoot() {
#ifdef FESA_SOURCE_DIR
return FESA_SOURCE_DIR;
#else
return ".";
#endif
}
fesa::Domain makeDomain() {
fesa::Domain domain;
domain.nodes[1] = {1, {0.0, 0.0, 0.0}};
domain.nodes[2] = {2, {1.0, 0.0, 0.0}};
domain.nodes[3] = {3, {1.0, 1.0, 0.0}};
domain.nodes[4] = {4, {0.0, 1.0, 0.0}};
domain.elements[10] = {10, fesa::ElementType::MITC4, {1, 2, 3, 4}, "all_elements"};
domain.steps.push_back({"Step-Results", "linear_static"});
domain.boundary_conditions.push_back({"1", 1, 6, 0.0});
return domain;
}
std::string readTextFile(const std::string& path) {
std::ifstream input(path);
if (!input) {
throw std::runtime_error("failed to open " + path);
}
std::ostringstream buffer;
buffer << input.rdbuf();
return buffer.str();
}
} // namespace
int main() {
const auto domain = makeDomain();
const fesa::DofManager dofs(domain);
std::vector<fesa::Real> u(static_cast<std::size_t>(dofs.fullDofCount()), 0.0);
std::vector<fesa::Real> rf(static_cast<std::size_t>(dofs.fullDofCount()), 0.0);
u[static_cast<std::size_t>(dofs.fullIndex(2, fesa::Dof::UZ))] = -0.25;
rf[static_cast<std::size_t>(dofs.fullIndex(1, fesa::Dof::UZ))] = 3.0;
fesa::InMemoryResultsWriter writer;
writer.writeLinearStatic(domain, dofs, u, rf);
const auto& result = writer.result();
check(result.schema_name == "FESA_RESULTS", "schema name changed");
check(result.schema_version == 1, "schema version changed");
check(result.solver_name == "FESA", "solver name changed");
check(result.dof_convention == "UX,UY,UZ,RX,RY,RZ", "DOF convention changed");
check(result.sign_convention == "Abaqus-compatible", "sign convention changed");
check(result.precision == "double", "precision metadata changed");
check(result.index_type == "int64", "index metadata changed");
check(result.node_ids.size() == domain.nodes.size(), "node model mirror changed");
check(result.element_types == std::vector<std::string>({"MITC4"}), "element type label changed");
check(result.steps.size() == 1, "result step count changed");
check(result.steps[0].name == "Step-Results", "step name changed");
check(result.steps[0].frames.size() == 1, "result frame count changed");
const auto& frame = result.steps[0].frames[0];
check(frame.frame_id == 0, "Phase 1 frame id changed");
check(frame.increment == 1, "Phase 1 increment changed");
check(frame.iteration == 0, "Phase 1 iteration changed");
check(frame.converged, "Phase 1 convergence flag changed");
check(frame.field_outputs.count("U") == 1, "U field missing");
check(frame.field_outputs.count("RF") == 1, "RF field missing");
const auto& u_field = frame.field_outputs.at("U");
const auto& rf_field = frame.field_outputs.at("RF");
check(u_field.position == "NODAL" && u_field.entity_type == "node" && u_field.basis == "GLOBAL",
"U field metadata changed");
check(rf_field.position == "NODAL" && rf_field.entity_type == "node" && rf_field.basis == "GLOBAL",
"RF field metadata changed");
check(u_field.component_labels == fesa::displacementComponentLabels(), "U component labels changed");
check(rf_field.component_labels == fesa::reactionComponentLabels(), "RF component labels changed");
const auto required_columns = fesa::displacementCsvRequiredColumns();
check(required_columns.size() == 7, "required displacement CSV column count changed");
check(required_columns.front() == "Node Label", "CSV node label column changed");
check(required_columns.back() == "UR-UR3", "CSV rotation column changed");
const auto missing_header = fesa::loadDisplacementCsvFromString("Node Label,U-U1,U-U2,U-U3,UR-UR1,UR-UR2\n"
"1,0,0,0,0,0\n",
"missing-header.csv");
check(fesa::containsDiagnostic(missing_header.diagnostics, "FESA-CSV-MISSING-COLUMN"),
"missing CSV header diagnostic changed");
const auto duplicate_node = fesa::loadDisplacementCsvFromString("Node Label,U-U1,U-U2,U-U3,UR-UR1,UR-UR2,UR-UR3\n"
"1,0,0,0,0,0,0\n"
"1,0,0,0,0,0,0\n",
"duplicate-node.csv");
check(fesa::containsDiagnostic(duplicate_node.diagnostics, "FESA-CSV-DUPLICATE-NODE"),
"duplicate CSV node diagnostic changed");
fesa::CsvDisplacementTable expected;
expected.rows[1] = {1, {0, 0, 0, 0, 0, 0}};
expected.rows[2] = {2, {0, 0, -0.25, 0, 0, 0}};
expected.rows[3] = {3, {0, 0, 0, 0, 0, 0}};
expected.rows[4] = {4, {0, 0, 0, 0, 0, 0}};
const auto comparison = fesa::compareDisplacements(u_field, expected, {1.0e-12, 1.0e-12, 1.0});
check(comparison.pass, "displacement comparator no longer matches by node id");
const auto quad02 = fesa::loadDisplacementCsv(sourceRoot() + "/references/quad_02_displacements.csv");
check(!fesa::hasError(quad02.diagnostics), "quad_02 displacement CSV no longer loads");
check(quad02.rows.size() == 121, "quad_02 displacement CSV row count changed");
return 0;
}