feat(cpp-object-oriented-modular-refactoring): step 19 - boundary-condition-policy
This commit is contained in:
@@ -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_),
|
||||
|
||||
Reference in New Issue
Block a user