test: strengthen core harness guardrails
This commit is contained in:
+28
-13
@@ -53,6 +53,11 @@ inline bool containsDiagnostic(const std::vector<Diagnostic>& diagnostics, const
|
||||
});
|
||||
}
|
||||
|
||||
inline Diagnostic makeDiagnostic(Severity severity, std::string code, std::string message, std::string keyword,
|
||||
std::string file = "<domain>", LocalIndex line = 0) {
|
||||
return {severity, std::move(code), std::move(message), {std::move(file), line, std::move(keyword)}};
|
||||
}
|
||||
|
||||
inline std::string trim(std::string text) {
|
||||
auto is_space = [](unsigned char c) { return std::isspace(c) != 0; };
|
||||
text.erase(text.begin(), std::find_if(text.begin(), text.end(), [&](unsigned char c) { return !is_space(c); }));
|
||||
@@ -624,11 +629,13 @@ inline std::optional<GlobalId> numericTarget(const std::string& target) {
|
||||
return parseInt64(target);
|
||||
}
|
||||
|
||||
inline std::vector<GlobalId> resolveNodeTarget(const Domain& domain, const std::string& target, std::vector<Diagnostic>* diagnostics = nullptr) {
|
||||
inline std::vector<GlobalId> resolveNodeTarget(const Domain& domain, const std::string& target, std::vector<Diagnostic>* diagnostics = nullptr,
|
||||
const std::string& diagnostic_keyword = "node target") {
|
||||
if (auto node_id = numericTarget(target)) {
|
||||
if (domain.nodes.count(*node_id) == 0) {
|
||||
if (diagnostics != nullptr) {
|
||||
diagnostics->push_back({Severity::Error, "FESA-VALIDATION-MISSING-NODE", "Missing node target: " + target, {}});
|
||||
diagnostics->push_back(
|
||||
makeDiagnostic(Severity::Error, "FESA-VALIDATION-MISSING-NODE", "Missing node target: " + target, diagnostic_keyword));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -637,7 +644,8 @@ inline std::vector<GlobalId> resolveNodeTarget(const Domain& domain, const std::
|
||||
auto set_it = domain.node_sets.find(Domain::key(target));
|
||||
if (set_it == domain.node_sets.end()) {
|
||||
if (diagnostics != nullptr) {
|
||||
diagnostics->push_back({Severity::Error, "FESA-VALIDATION-MISSING-NSET", "Missing node set: " + target, {}});
|
||||
diagnostics->push_back(
|
||||
makeDiagnostic(Severity::Error, "FESA-VALIDATION-MISSING-NSET", "Missing node set: " + target, diagnostic_keyword));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -660,44 +668,51 @@ inline const ShellSection* shellSectionForElement(const Domain& domain, GlobalId
|
||||
inline std::vector<Diagnostic> validateDomain(const Domain& domain) {
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
if (domain.elements.empty()) {
|
||||
diagnostics.push_back({Severity::Error, "FESA-SINGULAR-NO-ACTIVE-ELEMENTS", "No active elements exist in the current model", {}});
|
||||
diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-SINGULAR-NO-ACTIVE-ELEMENTS",
|
||||
"No active elements exist in the current model", "analysis model"));
|
||||
}
|
||||
if (domain.boundary_conditions.empty()) {
|
||||
diagnostics.push_back({Severity::Warning, "FESA-SINGULAR-NO-BOUNDARY", "No boundary constraints are defined", {}});
|
||||
diagnostics.push_back(makeDiagnostic(Severity::Warning, "FESA-SINGULAR-NO-BOUNDARY", "No boundary constraints are defined", "boundary"));
|
||||
}
|
||||
for (const auto& [id, element] : domain.elements) {
|
||||
for (GlobalId node_id : element.node_ids) {
|
||||
if (domain.nodes.count(node_id) == 0) {
|
||||
diagnostics.push_back({Severity::Error, "FESA-VALIDATION-ELEMENT-MISSING-NODE", "Element references missing node", {}});
|
||||
diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-VALIDATION-ELEMENT-MISSING-NODE",
|
||||
"Element " + std::to_string(id) + " references missing node " + std::to_string(node_id),
|
||||
"element"));
|
||||
}
|
||||
}
|
||||
const ShellSection* section = shellSectionForElement(domain, id);
|
||||
if (section == nullptr) {
|
||||
diagnostics.push_back({Severity::Error, "FESA-VALIDATION-MISSING-PROPERTY", "Element has no assigned shell section", {}});
|
||||
diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-VALIDATION-MISSING-PROPERTY",
|
||||
"Element " + std::to_string(id) + " has no assigned shell section", "element"));
|
||||
}
|
||||
}
|
||||
for (const ShellSection& section : domain.shell_sections) {
|
||||
if (domain.element_sets.count(Domain::key(section.element_set)) == 0) {
|
||||
diagnostics.push_back({Severity::Error, "FESA-VALIDATION-MISSING-ELSET", "Shell section references missing element set: " + section.element_set, {}});
|
||||
diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-VALIDATION-MISSING-ELSET",
|
||||
"Shell section references missing element set: " + section.element_set, "shell section"));
|
||||
}
|
||||
auto material_it = domain.materials.find(Domain::key(section.material));
|
||||
if (material_it == domain.materials.end()) {
|
||||
diagnostics.push_back({Severity::Error, "FESA-VALIDATION-MISSING-MATERIAL", "Shell section references missing material: " + section.material, {}});
|
||||
diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-VALIDATION-MISSING-MATERIAL",
|
||||
"Shell section references missing material: " + section.material, "shell section"));
|
||||
} else if (material_it->second.elastic_modulus <= 0.0) {
|
||||
diagnostics.push_back({Severity::Error, "FESA-VALIDATION-INCOMPLETE-MATERIAL", "Material has no valid elastic constants: " + section.material, {}});
|
||||
diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-VALIDATION-INCOMPLETE-MATERIAL",
|
||||
"Material has no valid elastic constants: " + section.material, "material"));
|
||||
}
|
||||
}
|
||||
for (const BoundaryCondition& boundary : domain.boundary_conditions) {
|
||||
(void)resolveNodeTarget(domain, boundary.target, &diagnostics);
|
||||
(void)resolveNodeTarget(domain, boundary.target, &diagnostics, "boundary");
|
||||
}
|
||||
for (const NodalLoad& load : domain.loads) {
|
||||
(void)resolveNodeTarget(domain, load.target, &diagnostics);
|
||||
(void)resolveNodeTarget(domain, load.target, &diagnostics, "cload");
|
||||
}
|
||||
const bool any_nonzero_load = std::any_of(domain.loads.begin(), domain.loads.end(), [](const NodalLoad& load) {
|
||||
return std::fabs(load.magnitude) > 0.0;
|
||||
});
|
||||
if (!any_nonzero_load) {
|
||||
diagnostics.push_back({Severity::Warning, "FESA-SINGULAR-NO-NONZERO-LOAD", "No nonzero load is defined", {}});
|
||||
diagnostics.push_back(makeDiagnostic(Severity::Warning, "FESA-SINGULAR-NO-NONZERO-LOAD", "No nonzero load is defined", "cload"));
|
||||
}
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user