feat: strengthen dof manager foundation
This commit is contained in:
+74
-16
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user