feat: strengthen dof manager foundation

This commit is contained in:
NINI
2026-05-04 13:18:28 +09:00
parent ac72f4ccd7
commit b9b0963d50
5 changed files with 223 additions and 22 deletions
+74 -16
View File
@@ -937,6 +937,11 @@ inline std::vector<Diagnostic> validateDomain(const Domain& domain) {
return diagnostics;
}
struct DofAddress {
GlobalId node_id = 0;
Dof dof = Dof::UX;
};
class DofManager {
public:
explicit DofManager(const Domain& domain) {
@@ -951,6 +956,9 @@ class DofManager {
}
}
for (const BoundaryCondition& boundary : domain.boundary_conditions) {
if (!validAbaqusDofRange(boundary.first_dof, boundary.last_dof)) {
continue;
}
for (GlobalId node_id : resolveNodeTarget(domain, boundary.target)) {
for (int dof = boundary.first_dof; dof <= boundary.last_dof; ++dof) {
constrained_.insert(std::make_pair(node_id, dof - 1));
@@ -964,6 +972,7 @@ class DofManager {
free_full_indices_.push_back(full_index);
} else {
equation_by_key_[key] = -1;
constrained_full_indices_.push_back(full_index);
}
}
}
@@ -976,6 +985,10 @@ class DofManager {
return static_cast<LocalIndex>(free_full_indices_.size());
}
LocalIndex constrainedDofCount() const {
return static_cast<LocalIndex>(constrained_full_indices_.size());
}
const std::vector<GlobalId>& nodeIds() const {
return node_ids_;
}
@@ -984,6 +997,15 @@ class DofManager {
return free_full_indices_;
}
const std::vector<LocalIndex>& constrainedFullIndices() const {
return constrained_full_indices_;
}
DofAddress fullDof(LocalIndex full_index) const {
const auto& key = all_dofs_.at(static_cast<std::size_t>(full_index));
return {key.first, static_cast<Dof>(key.second)};
}
LocalIndex fullIndex(GlobalId node_id, Dof dof) const {
return full_index_by_key_.at(std::make_pair(node_id, dofIndex(dof)));
}
@@ -996,14 +1018,45 @@ class DofManager {
return constrained_.count(std::make_pair(node_id, dofIndex(dof))) != 0;
}
std::vector<Real> reduceFullVector(const std::vector<Real>& full) const {
std::vector<Real> reduced;
reduced.reserve(free_full_indices_.size());
for (LocalIndex full_index : free_full_indices_) {
reduced.push_back(full.at(static_cast<std::size_t>(full_index)));
}
return reduced;
}
std::vector<Real> reconstructFullVector(const std::vector<Real>& reduced) const {
std::vector<Real> full(static_cast<std::size_t>(fullDofCount()), 0.0);
for (std::size_t i = 0; i < free_full_indices_.size(); ++i) {
full[static_cast<std::size_t>(free_full_indices_[i])] = reduced[i];
full[static_cast<std::size_t>(free_full_indices_[i])] = reduced.at(i);
}
return full;
}
std::array<LocalIndex, 24> elementFullDofIndices(const Element& element) const {
std::array<LocalIndex, 24> indices{};
for (LocalIndex node = 0; node < 4; ++node) {
for (Dof dof : allDofs()) {
const LocalIndex local = 6 * node + dofIndex(dof);
indices[static_cast<std::size_t>(local)] = fullIndex(element.node_ids[static_cast<std::size_t>(node)], dof);
}
}
return indices;
}
std::array<EquationId, 24> elementEquationIds(const Element& element) const {
std::array<EquationId, 24> equations{};
for (LocalIndex node = 0; node < 4; ++node) {
for (Dof dof : allDofs()) {
const LocalIndex local = 6 * node + dofIndex(dof);
equations[static_cast<std::size_t>(local)] = equation(element.node_ids[static_cast<std::size_t>(node)], dof);
}
}
return equations;
}
private:
std::vector<GlobalId> node_ids_;
std::vector<std::pair<GlobalId, int>> all_dofs_;
@@ -1011,6 +1064,7 @@ class DofManager {
std::map<std::pair<GlobalId, int>, LocalIndex> full_index_by_key_;
std::map<std::pair<GlobalId, int>, EquationId> equation_by_key_;
std::vector<LocalIndex> free_full_indices_;
std::vector<LocalIndex> constrained_full_indices_;
};
class DenseMatrix {
@@ -1056,6 +1110,18 @@ class DenseMatrix {
std::vector<Real> values_;
};
inline std::vector<Real> recoverFullReaction(const DenseMatrix& k_full, const std::vector<Real>& u_full, const std::vector<Real>& f_full) {
if (k_full.rows() != k_full.cols() || static_cast<LocalIndex>(u_full.size()) != k_full.cols() ||
static_cast<LocalIndex>(f_full.size()) != k_full.rows()) {
throw std::runtime_error("full reaction size mismatch");
}
std::vector<Real> reaction = k_full.multiply(u_full);
for (std::size_t i = 0; i < reaction.size(); ++i) {
reaction[i] -= f_full[i];
}
return reaction;
}
struct SolveResult {
std::vector<Real> x;
std::vector<Diagnostic> diagnostics;
@@ -1378,17 +1444,12 @@ inline AssemblyResult assembleSystem(const Domain& domain, const DofManager& dof
coordinates[i] = domain.nodes.at(element.node_ids[i]).coordinates;
}
DenseMatrix ke = kernel.stiffness(coordinates, material_it->second.elastic_modulus, material_it->second.poisson_ratio, section->thickness, options);
for (LocalIndex a = 0; a < 4; ++a) {
for (Dof da : allDofs()) {
const LocalIndex ia = dofs.fullIndex(element.node_ids[static_cast<std::size_t>(a)], da);
const LocalIndex la = 6 * a + dofIndex(da);
for (LocalIndex b = 0; b < 4; ++b) {
for (Dof db : allDofs()) {
const LocalIndex ib = dofs.fullIndex(element.node_ids[static_cast<std::size_t>(b)], db);
const LocalIndex lb = 6 * b + dofIndex(db);
result.k_full.add(ia, ib, ke(la, lb));
}
}
const auto element_full_indices = dofs.elementFullDofIndices(element);
for (LocalIndex a = 0; a < 24; ++a) {
const LocalIndex ia = element_full_indices[static_cast<std::size_t>(a)];
for (LocalIndex b = 0; b < 24; ++b) {
const LocalIndex ib = element_full_indices[static_cast<std::size_t>(b)];
result.k_full.add(ia, ib, ke(a, b));
}
}
}
@@ -1546,10 +1607,7 @@ class LinearStaticAnalysis final : public Analysis {
}
result.state.u_full = dofs.reconstructFullVector(solved.x);
result.state.f_external_full = assembly.f_full;
result.state.reaction_full = assembly.k_full.multiply(result.state.u_full);
for (std::size_t i = 0; i < result.state.reaction_full.size(); ++i) {
result.state.reaction_full[i] -= result.state.f_external_full[i];
}
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);