feat(cpp-object-oriented-modular-refactoring): step 19 - boundary-condition-policy

This commit is contained in:
KOKO\Mimi
2026-08-16 11:23:20 +09:00
parent f26e0a61a8
commit 64a43948ef
27 changed files with 919 additions and 365 deletions
+81 -40
View File
@@ -2,6 +2,7 @@
#include <algorithm>
#include <array>
#include <cmath>
#include <cstddef>
#include <limits>
#include <stdexcept>
@@ -47,21 +48,6 @@ std::vector<DofComponent> FullNodeComponents() {
DofComponent::kUrx, DofComponent::kUry, DofComponent::kUrz};
}
std::vector<EntityIndex> ExpandBoundaryTarget(
const SourceTargetResolver& resolver, const BoundaryCondition& boundary) {
auto resolved =
resolver.Resolve({SourceEntityKind::kNode, "", boundary.target});
if (!resolved.HasValue()) {
return {};
}
std::vector<EntityIndex> indices;
indices.reserve(resolved.Value().size());
for (const auto& target : resolved.Value()) {
indices.push_back(target.entity_index);
}
return indices;
}
void AppendScatter(std::vector<std::vector<std::size_t>>& columns_by_row,
const std::vector<std::size_t>& scatter) {
for (const std::size_t row : scatter) {
@@ -124,7 +110,8 @@ Result<DofManager> DofManager::Create(const AnalysisModel& model) {
}
DofManager dofs;
const Status status = dofs.BuildLayouts(model, layouts);
const Status status =
dofs.BuildLayouts(model, layouts, model.Step().BoundaryConditions());
if (!status.IsOk()) {
return Result<DofManager>::Failure(status);
}
@@ -133,16 +120,24 @@ Result<DofManager> DofManager::Create(const AnalysisModel& model) {
Status DofManager::Build(const AnalysisModel& analysis_model,
const ElementView& elements) {
return Build(analysis_model, elements,
analysis_model.Step().BoundaryConditions());
}
Status DofManager::Build(const AnalysisModel& analysis_model,
const ElementView& elements,
const BoundaryConditionView& boundaries) {
std::vector<ElementDofLayout> layouts;
layouts.reserve(elements.size());
for (const auto& element : elements) {
layouts.push_back(element.get().DofLayout());
}
return BuildLayouts(analysis_model, layouts);
return BuildLayouts(analysis_model, layouts, boundaries);
}
Status DofManager::BuildLayouts(const AnalysisModel& analysis_model,
const std::vector<ElementDofLayout>& layouts) {
const std::vector<ElementDofLayout>& layouts,
const BoundaryConditionView& boundaries) {
const Domain& domain = analysis_model.GetDomain();
if (domain.Nodes().size() >
(std::numeric_limits<std::size_t>::max)() / kDofsPerNode) {
@@ -177,29 +172,69 @@ Status DofManager::BuildLayouts(const AnalysisModel& analysis_model,
const SourceTargetResolver target_resolver{target_index};
const std::size_t full_count = domain.Nodes().size() * kDofsPerNode;
std::vector<std::optional<double>> prescribed_by_full_dof(full_count);
for (const EntityIndex boundary_index :
analysis_model.ActiveBoundaryConditions()) {
const auto& boundary =
analysis_model.Step().Boundaries().at(boundary_index);
const auto target = ExpandBoundaryTarget(target_resolver, boundary);
for (const EntityIndex node : target) {
for (int component = boundary.first_dof; component <= boundary.last_dof;
++component) {
const std::size_t full_dof =
static_cast<std::size_t>(node) * kDofsPerNode +
static_cast<std::size_t>(component - 1);
auto& prescribed = prescribed_by_full_dof[full_dof];
if (prescribed && *prescribed != boundary.value) {
return Status::Failure(
FailureCategory::kInput,
{{Severity::kError, "conflicting-boundary-condition",
boundary.location, "BOUNDARY", boundary.target,
"Expanded boundary rows prescribe different values to one "
"node/DOF."}});
}
prescribed = boundary.value;
DofManager full_dof_map;
full_dof_map.full_dof_count_ = full_count;
const BoundaryConditionContext context{domain, full_dof_map, target_resolver};
std::vector<std::vector<ConstraintDefinition>> definitions_by_boundary;
definitions_by_boundary.reserve(boundaries.size());
for (std::size_t source_order = 0U; source_order < boundaries.size();
++source_order) {
auto definitions =
boundaries[source_order].get().ResolveConstraints(context);
if (!definitions.HasValue()) {
return definitions.GetStatus();
}
std::vector<std::size_t> seen_full_dofs;
seen_full_dofs.reserve(definitions.Value().size());
for (const auto& definition : definitions.Value()) {
if (definition.source_order != source_order) {
return DofFailure(
"invalid-constraint-order", analysis_model.Step().Location(),
std::to_string(definition.source_order),
"Every constraint definition must retain its supplying boundary "
"source order.");
}
if (definition.full_dof_index >= full_count) {
return DofFailure(
"invalid-constraint-index", analysis_model.Step().Location(),
std::to_string(definition.full_dof_index),
"A constraint definition full-DOF index is outside the active "
"model.");
}
if (!std::isfinite(definition.prescribed_value)) {
return DofFailure(
"nonfinite-prescribed-value", analysis_model.Step().Location(),
std::to_string(source_order),
"A constraint definition prescribed value must be finite.");
}
if (std::find(seen_full_dofs.begin(), seen_full_dofs.end(),
definition.full_dof_index) != seen_full_dofs.end()) {
return DofFailure(
"duplicate-constraint-definition", analysis_model.Step().Location(),
std::to_string(definition.full_dof_index),
"One boundary must not emit the same full DOF more than once.");
}
seen_full_dofs.push_back(definition.full_dof_index);
}
definitions_by_boundary.push_back(std::move(definitions.Value()));
}
std::vector<std::optional<double>> prescribed_by_full_dof(full_count);
for (std::size_t source_order = 0U;
source_order < definitions_by_boundary.size(); ++source_order) {
const auto& definitions = definitions_by_boundary[source_order];
for (const auto& definition : definitions) {
auto& prescribed = prescribed_by_full_dof[definition.full_dof_index];
if (prescribed && *prescribed != definition.prescribed_value) {
return Status::Failure(
FailureCategory::kInput,
{{Severity::kError, "conflicting-boundary-condition",
boundaries[source_order].get().Location(), "BOUNDARY",
boundaries[source_order].get().TargetIdentity(),
"Expanded boundary rows prescribe different values to one "
"node/DOF."}});
}
prescribed = definition.prescribed_value;
}
}
@@ -356,6 +391,12 @@ Status DofManager::ValidateInvariants() const {
"Full, free, constrained, prescribed, and equation dimensions must "
"agree.");
}
for (std::size_t index = 0U; index < prescribed_values_.Size(); ++index) {
if (!std::isfinite(prescribed_values_[index])) {
return DofFailure("nonfinite-prescribed-value", {}, std::to_string(index),
"Prescribed displacement values must remain finite.");
}
}
if (HasAdjacentDuplicate(free_dofs_)) {
return DofFailure("duplicate-dof-mapping", {},
std::to_string(full_dof_count_),