138 lines
6.4 KiB
C++
138 lines
6.4 KiB
C++
#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 required_reaction_columns = fesa::reactionCsvRequiredColumns();
|
|
check(required_reaction_columns.size() == 7, "required reaction CSV column count changed");
|
|
check(required_reaction_columns.front() == "Node Label", "reaction CSV node label column changed");
|
|
check(required_reaction_columns.back() == "RM-RM3", "reaction CSV moment 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");
|
|
|
|
fesa::CsvReactionTable expected_reactions;
|
|
expected_reactions.rows[1] = {1, {0, 0, 3.0, 0, 0, 0}};
|
|
expected_reactions.rows[2] = {2, {0, 0, 0, 0, 0, 0}};
|
|
expected_reactions.rows[3] = {3, {0, 0, 0, 0, 0, 0}};
|
|
expected_reactions.rows[4] = {4, {0, 0, 0, 0, 0, 0}};
|
|
const auto reaction_comparison = fesa::compareReactions(rf_field, expected_reactions, {1.0e-12, 1.0e-12, 1.0});
|
|
check(reaction_comparison.pass, "reaction 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");
|
|
|
|
const auto quad02_reactions = fesa::loadReactionCsv(sourceRoot() + "/references/quad_02_reactionforces.csv");
|
|
check(!fesa::hasError(quad02_reactions.diagnostics), "quad_02 reaction CSV no longer loads");
|
|
check(quad02_reactions.rows.size() == 121, "quad_02 reaction CSV row count changed");
|
|
|
|
return 0;
|
|
}
|