feat: add linear static workflow model
This commit is contained in:
+93
-2
@@ -229,6 +229,14 @@ struct Node {
|
||||
|
||||
enum class ElementType { MITC4 };
|
||||
|
||||
inline std::string elementTypeLabel(ElementType type) {
|
||||
switch (type) {
|
||||
case ElementType::MITC4:
|
||||
return "MITC4";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
struct Element {
|
||||
GlobalId id = 0;
|
||||
ElementType type = ElementType::MITC4;
|
||||
@@ -953,6 +961,61 @@ inline std::vector<Diagnostic> validateDomain(const Domain& domain) {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
struct AnalysisModel {
|
||||
StepDefinition step;
|
||||
std::vector<GlobalId> active_element_ids;
|
||||
std::vector<std::size_t> active_boundary_condition_indices;
|
||||
std::vector<std::size_t> active_load_indices;
|
||||
std::vector<std::size_t> active_shell_section_indices;
|
||||
std::vector<std::string> active_material_keys;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
|
||||
bool ok() const {
|
||||
return !hasError(diagnostics);
|
||||
}
|
||||
};
|
||||
|
||||
inline AnalysisModel buildLinearStaticAnalysisModel(const Domain& domain, LocalIndex step_index = 0) {
|
||||
AnalysisModel model;
|
||||
if (domain.steps.empty()) {
|
||||
model.step = {"Step-1", "linear_static"};
|
||||
} else {
|
||||
if (step_index < 0 || step_index >= static_cast<LocalIndex>(domain.steps.size())) {
|
||||
model.diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-ANALYSIS-STEP-INDEX",
|
||||
"Requested analysis step index is out of range", "analysis model"));
|
||||
model.step = domain.steps.front();
|
||||
} else {
|
||||
model.step = domain.steps[static_cast<std::size_t>(step_index)];
|
||||
}
|
||||
}
|
||||
if (domain.steps.size() > 1) {
|
||||
model.diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-ANALYSIS-MULTIPLE-STEPS",
|
||||
"Phase 1 execution supports one active linear static step", "analysis model"));
|
||||
}
|
||||
if (model.step.analysis_type != "linear_static") {
|
||||
model.diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-ANALYSIS-UNSUPPORTED-STEP",
|
||||
"Only linear static steps are supported in Phase 1", "analysis model"));
|
||||
}
|
||||
for (const auto& [element_id, element] : domain.elements) {
|
||||
(void)element;
|
||||
model.active_element_ids.push_back(element_id);
|
||||
}
|
||||
for (std::size_t i = 0; i < domain.boundary_conditions.size(); ++i) {
|
||||
model.active_boundary_condition_indices.push_back(i);
|
||||
}
|
||||
for (std::size_t i = 0; i < domain.loads.size(); ++i) {
|
||||
model.active_load_indices.push_back(i);
|
||||
}
|
||||
for (std::size_t i = 0; i < domain.shell_sections.size(); ++i) {
|
||||
model.active_shell_section_indices.push_back(i);
|
||||
}
|
||||
for (const auto& [material_key, material] : domain.materials) {
|
||||
(void)material;
|
||||
model.active_material_keys.push_back(material_key);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
struct DofAddress {
|
||||
GlobalId node_id = 0;
|
||||
Dof dof = Dof::UX;
|
||||
@@ -2291,6 +2354,7 @@ struct ResultFile {
|
||||
std::vector<GlobalId> node_ids;
|
||||
std::vector<Vec3> coordinates;
|
||||
std::vector<GlobalId> element_ids;
|
||||
std::vector<std::string> element_types;
|
||||
std::vector<std::array<GlobalId, 4>> connectivity;
|
||||
std::vector<ResultStep> steps;
|
||||
};
|
||||
@@ -2298,6 +2362,12 @@ struct ResultFile {
|
||||
class InMemoryResultsWriter {
|
||||
public:
|
||||
void writeLinearStatic(const Domain& domain, const DofManager& dofs, const std::vector<Real>& u_full, const std::vector<Real>& rf_full) {
|
||||
const auto model = buildLinearStaticAnalysisModel(domain);
|
||||
writeLinearStatic(domain, model, dofs, u_full, rf_full);
|
||||
}
|
||||
|
||||
void writeLinearStatic(const Domain& domain, const AnalysisModel& model, const DofManager& dofs,
|
||||
const std::vector<Real>& u_full, const std::vector<Real>& rf_full) {
|
||||
result_ = ResultFile{};
|
||||
for (const auto& [node_id, node] : domain.nodes) {
|
||||
result_.node_ids.push_back(node_id);
|
||||
@@ -2305,10 +2375,11 @@ class InMemoryResultsWriter {
|
||||
}
|
||||
for (const auto& [element_id, element] : domain.elements) {
|
||||
result_.element_ids.push_back(element_id);
|
||||
result_.element_types.push_back(elementTypeLabel(element.type));
|
||||
result_.connectivity.push_back(element.node_ids);
|
||||
}
|
||||
ResultStep step;
|
||||
step.name = domain.steps.empty() ? "Step-1" : domain.steps.front().name;
|
||||
step.name = model.step.name.empty() ? "Step-1" : model.step.name;
|
||||
ResultFrame frame;
|
||||
frame.frame_id = 0;
|
||||
frame.field_outputs["U"] = buildNodalField("U", displacementComponentLabels(), "Nodal displacement and rotation", domain, dofs, u_full);
|
||||
@@ -2355,6 +2426,7 @@ struct AnalysisState {
|
||||
};
|
||||
|
||||
struct AnalysisResult {
|
||||
AnalysisModel model;
|
||||
AnalysisState state;
|
||||
ResultFile result_file;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
@@ -2391,6 +2463,11 @@ class LinearStaticAnalysis final : public Analysis {
|
||||
|
||||
protected:
|
||||
void solve(const Domain& domain, AnalysisResult& result) const override {
|
||||
result.model = buildLinearStaticAnalysisModel(domain);
|
||||
result.diagnostics.insert(result.diagnostics.end(), result.model.diagnostics.begin(), result.model.diagnostics.end());
|
||||
if (hasError(result.diagnostics)) {
|
||||
return;
|
||||
}
|
||||
DofManager dofs(domain);
|
||||
if (dofs.freeDofCount() == 0) {
|
||||
result.diagnostics.push_back(makeDiagnostic(Severity::Error, "FESA-SINGULAR-NO-FREE-DOFS",
|
||||
@@ -2424,7 +2501,7 @@ class LinearStaticAnalysis final : public Analysis {
|
||||
result.state.reaction_full = recoverFullReaction(assembly.k_full, result.state.u_full, result.state.f_external_full);
|
||||
result.state.converged = true;
|
||||
InMemoryResultsWriter writer;
|
||||
writer.writeLinearStatic(domain, dofs, result.state.u_full, result.state.reaction_full);
|
||||
writer.writeLinearStatic(domain, result.model, dofs, result.state.u_full, result.state.reaction_full);
|
||||
result.result_file = writer.result();
|
||||
}
|
||||
|
||||
@@ -2437,6 +2514,20 @@ class LinearStaticAnalysis final : public Analysis {
|
||||
const LinearSolver* solver_ = nullptr;
|
||||
};
|
||||
|
||||
inline AnalysisResult runLinearStaticInputString(const std::string& text,
|
||||
const std::string& source_name = "<memory>",
|
||||
const LinearSolver* solver = nullptr) {
|
||||
AbaqusInputParser parser;
|
||||
const auto parsed = parser.parseString(text, source_name);
|
||||
if (!parsed.ok()) {
|
||||
AnalysisResult result;
|
||||
result.diagnostics = parsed.diagnostics;
|
||||
return result;
|
||||
}
|
||||
LinearStaticAnalysis analysis(solver);
|
||||
return analysis.run(parsed.domain);
|
||||
}
|
||||
|
||||
struct CsvDisplacementRow {
|
||||
GlobalId node_id = 0;
|
||||
std::array<Real, 6> values{};
|
||||
|
||||
Reference in New Issue
Block a user