feat(cpp-object-oriented-modular-refactoring): step 15 - generic-dof-manager
This commit is contained in:
@@ -25,79 +25,6 @@ Status LoadFailure(const std::string& code, const SourceLocation& location,
|
||||
{{Severity::kError, code, location, keyword, identity, message}});
|
||||
}
|
||||
|
||||
/// @brief Checks that equation-space indices preserve stable full-DOF order.
|
||||
bool IsStrictlyIncreasing(const std::vector<std::size_t>& values) {
|
||||
return std::adjacent_find(
|
||||
values.begin(), values.end(),
|
||||
[](const std::size_t left, const std::size_t right) {
|
||||
return left >= right;
|
||||
}) == values.end();
|
||||
}
|
||||
|
||||
/// @brief Validates the full/free/constrained partition used by load assembly.
|
||||
Status ValidateDofOrder(const DofManager& dofs,
|
||||
const std::size_t expected_full_count,
|
||||
const SourceLocation& location) {
|
||||
const std::size_t full_count = dofs.FullDofCount();
|
||||
const auto& free_dofs = dofs.FreeDofs();
|
||||
const auto& constrained_dofs = dofs.ConstrainedDofs();
|
||||
if (full_count != expected_full_count ||
|
||||
free_dofs.size() != dofs.FreeDofCount() ||
|
||||
constrained_dofs.size() != dofs.ConstrainedDofCount() ||
|
||||
dofs.PrescribedValues().Size() != constrained_dofs.size() ||
|
||||
constrained_dofs.size() > full_count ||
|
||||
free_dofs.size() != full_count - constrained_dofs.size()) {
|
||||
return LoadFailure("invalid-load-dimensions", location, "LOAD_ASSEMBLER",
|
||||
std::to_string(full_count),
|
||||
"Full, free, constrained, prescribed, and model "
|
||||
"dimensions must agree.");
|
||||
}
|
||||
if (!IsStrictlyIncreasing(free_dofs) ||
|
||||
!IsStrictlyIncreasing(constrained_dofs)) {
|
||||
return LoadFailure(
|
||||
"invalid-load-order", location, "LOAD_ASSEMBLER",
|
||||
std::to_string(full_count),
|
||||
"Free and constrained DOFs must use stable increasing full-DOF order.");
|
||||
}
|
||||
|
||||
std::vector<unsigned char> ownership(full_count, 0U);
|
||||
try {
|
||||
for (std::size_t equation = 0U; equation < free_dofs.size(); ++equation) {
|
||||
const std::size_t full_dof = free_dofs[equation];
|
||||
if (full_dof >= full_count || ownership[full_dof] != 0U ||
|
||||
dofs.FreeEquation(full_dof) != equation) {
|
||||
return LoadFailure(
|
||||
"invalid-load-order", location, "LOAD_ASSEMBLER",
|
||||
std::to_string(full_dof),
|
||||
"Free equation numbering must match stable full-DOF order.");
|
||||
}
|
||||
ownership[full_dof] = 1U;
|
||||
}
|
||||
for (const std::size_t full_dof : constrained_dofs) {
|
||||
if (full_dof >= full_count || ownership[full_dof] != 0U ||
|
||||
dofs.FreeEquation(full_dof).has_value()) {
|
||||
return LoadFailure(
|
||||
"invalid-load-order", location, "LOAD_ASSEMBLER",
|
||||
std::to_string(full_dof),
|
||||
"Constrained DOFs must be unique and absent from free equations.");
|
||||
}
|
||||
ownership[full_dof] = 2U;
|
||||
}
|
||||
} catch (const std::out_of_range&) {
|
||||
return LoadFailure(
|
||||
"invalid-load-dimensions", location, "LOAD_ASSEMBLER",
|
||||
std::to_string(full_count),
|
||||
"DofManager equation storage must cover every full DOF.");
|
||||
}
|
||||
if (std::find(ownership.begin(), ownership.end(), 0U) != ownership.end()) {
|
||||
return LoadFailure(
|
||||
"invalid-load-order", location, "LOAD_ASSEMBLER",
|
||||
std::to_string(full_count),
|
||||
"Free and constrained DOFs must partition the full range.");
|
||||
}
|
||||
return Status::Ok();
|
||||
}
|
||||
|
||||
Result<std::vector<EntityIndex>> ResolveTarget(
|
||||
const SourceTargetResolver& resolver, const Domain& domain,
|
||||
const NodalLoad& load) {
|
||||
@@ -207,8 +134,13 @@ Result<Vector> LoadAssembler::AssembleFullNodalLoad(const AnalysisModel& model,
|
||||
"The semantic node count cannot be represented in full-DOF order."));
|
||||
}
|
||||
const std::size_t expected_full_count = domain.Nodes().size() * kDofsPerNode;
|
||||
const Status dof_status =
|
||||
ValidateDofOrder(dofs, expected_full_count, {domain.SourcePath(), 0U});
|
||||
if (dofs.FullDofCount() != expected_full_count) {
|
||||
return Result<Vector>::Failure(LoadFailure(
|
||||
"invalid-load-dimensions", {domain.SourcePath(), 0U}, "LOAD_ASSEMBLER",
|
||||
std::to_string(dofs.FullDofCount()),
|
||||
"The DofManager full dimension must match the active model."));
|
||||
}
|
||||
const Status dof_status = dofs.ValidateInvariants();
|
||||
if (!dof_status.IsOk()) {
|
||||
return Result<Vector>::Failure(dof_status);
|
||||
}
|
||||
@@ -296,7 +228,13 @@ Result<Vector> LoadAssembler::EffectiveFreeRhs(const Vector& full_load,
|
||||
const Vector& prescribed_values,
|
||||
const DofManager& dofs) {
|
||||
const SourceLocation location{{}, 0U};
|
||||
const Status dof_status = ValidateDofOrder(dofs, full_load.Size(), location);
|
||||
if (dofs.FullDofCount() != full_load.Size()) {
|
||||
return Result<Vector>::Failure(
|
||||
LoadFailure("invalid-load-dimensions", location, "LOAD_ASSEMBLER",
|
||||
std::to_string(dofs.FullDofCount()),
|
||||
"The DofManager full dimension must match the full load."));
|
||||
}
|
||||
const Status dof_status = dofs.ValidateInvariants();
|
||||
if (!dof_status.IsOk()) {
|
||||
return Result<Vector>::Failure(dof_status);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user