feat(solid): add Hex8 input and three-DOF semantics
This commit is contained in:
@@ -116,8 +116,12 @@ Result<DofManager> DofManager::Create(const AnalysisModel& model) {
|
||||
"An active element index is outside the Domain."));
|
||||
}
|
||||
const auto& definition = domain.Elements()[element_index];
|
||||
layouts.push_back({definition.SourceId(), definition.NodeIndices(),
|
||||
FullNodeComponents()});
|
||||
layouts.push_back(
|
||||
{definition.SourceId(), definition.NodeIndices(),
|
||||
domain.IsSolid()
|
||||
? std::vector<DofComponent>{DofComponent::kUx, DofComponent::kUy,
|
||||
DofComponent::kUz}
|
||||
: FullNodeComponents()});
|
||||
}
|
||||
|
||||
DofManager dofs;
|
||||
@@ -305,6 +309,19 @@ Status DofManager::BuildLayouts(const AnalysisModel& analysis_model,
|
||||
++source_order) {
|
||||
const EntityIndex definition_index =
|
||||
analysis_model.ActiveElements()[source_order];
|
||||
if (domain.IsSolid()) {
|
||||
const std::vector<DofComponent> translations{
|
||||
DofComponent::kUx, DofComponent::kUy, DofComponent::kUz};
|
||||
if (layouts[source_order].components_per_node != translations ||
|
||||
definition_index >= domain.Elements().Size() ||
|
||||
layouts[source_order].node_indices !=
|
||||
domain.Elements()[definition_index].NodeIndices()) {
|
||||
return DofFailure(
|
||||
"invalid-solid-element-layout", {domain.SourcePath(), 0U},
|
||||
std::to_string(source_order),
|
||||
"Solid layouts require source-ordered eight nodes and UX/UY/UZ.");
|
||||
}
|
||||
}
|
||||
if (definition_index >= domain.Elements().Size() ||
|
||||
!SameSourceIdentity(layouts[source_order].source_id,
|
||||
domain.Elements()[definition_index].SourceId())) {
|
||||
@@ -318,10 +335,13 @@ Status DofManager::BuildLayouts(const AnalysisModel& analysis_model,
|
||||
|
||||
const SourceTargetIndex target_index = SourceTargetIndex::FromDomain(domain);
|
||||
const SourceTargetResolver target_resolver{target_index};
|
||||
const std::size_t full_count = domain.Nodes().size() * kDofsPerNode;
|
||||
const std::size_t component_count = domain.IsSolid() ? 3U : kDofsPerNode;
|
||||
const std::size_t full_count = domain.Nodes().size() * component_count;
|
||||
|
||||
DofManager full_dof_map;
|
||||
full_dof_map.full_dof_count_ = full_count;
|
||||
full_dof_map.profile_ =
|
||||
domain.IsSolid() ? DofProfile::kSolidStructural : DofProfile::kStructural;
|
||||
const BoundaryConditionContext context{domain, full_dof_map, target_resolver};
|
||||
std::vector<std::vector<ConstraintDefinition>> definitions_by_boundary;
|
||||
definitions_by_boundary.reserve(boundaries.size());
|
||||
@@ -417,6 +437,7 @@ Status DofManager::BuildLayouts(const AnalysisModel& analysis_model,
|
||||
std::move(constrained_dofs),
|
||||
std::move(prescribed_values),
|
||||
{}};
|
||||
candidate.profile_ = full_dof_map.profile_;
|
||||
candidate.element_scatters_.reserve(layouts.size());
|
||||
for (const auto& layout : layouts) {
|
||||
auto scatter = candidate.ElementScatter(layout);
|
||||
@@ -441,6 +462,10 @@ std::size_t DofManager::FullDofCount() const noexcept {
|
||||
}
|
||||
|
||||
DofProfile DofManager::Profile() const noexcept { return profile_; }
|
||||
std::size_t DofManager::ComponentsPerNode() const noexcept {
|
||||
if (profile_ == DofProfile::kThermal) return kThermalDofsPerNode;
|
||||
return profile_ == DofProfile::kSolidStructural ? 3U : kDofsPerNode;
|
||||
}
|
||||
|
||||
std::size_t DofManager::FreeDofCount() const noexcept {
|
||||
return free_dofs_.size();
|
||||
@@ -452,15 +477,16 @@ std::size_t DofManager::ConstrainedDofCount() const noexcept {
|
||||
|
||||
std::size_t DofManager::FullDof(const EntityIndex node,
|
||||
const DofComponent component) const {
|
||||
if (profile_ != DofProfile::kStructural) {
|
||||
throw std::logic_error{"Structural components are invalid for thermal DOFs."};
|
||||
if (profile_ == DofProfile::kThermal) {
|
||||
throw std::logic_error{
|
||||
"Structural components are invalid for thermal DOFs."};
|
||||
}
|
||||
const std::size_t component_index = static_cast<std::size_t>(component);
|
||||
if (node >= full_dof_count_ / kDofsPerNode ||
|
||||
component_index >= kDofsPerNode) {
|
||||
if (node >= full_dof_count_ / ComponentsPerNode() ||
|
||||
component_index >= ComponentsPerNode()) {
|
||||
throw std::out_of_range{"Node or DOF component is out of range."};
|
||||
}
|
||||
return static_cast<std::size_t>(node) * kDofsPerNode + component_index;
|
||||
return static_cast<std::size_t>(node) * ComponentsPerNode() + component_index;
|
||||
}
|
||||
|
||||
std::size_t DofManager::FullThermalDof(
|
||||
@@ -481,7 +507,7 @@ std::optional<std::size_t> DofManager::FreeEquation(
|
||||
|
||||
Result<std::vector<std::size_t>> DofManager::ElementScatter(
|
||||
const ElementDofLayout& layout) const {
|
||||
if (profile_ != DofProfile::kStructural) {
|
||||
if (profile_ == DofProfile::kThermal) {
|
||||
return Result<std::vector<std::size_t>>::Failure(DofFailure(
|
||||
"invalid-dof-profile", {}, layout.source_id.source_label_text,
|
||||
"Structural layouts are invalid for a thermal mapping."));
|
||||
@@ -501,8 +527,8 @@ Result<std::vector<std::size_t>> DofManager::ElementScatter(
|
||||
for (const EntityIndex node : layout.node_indices) {
|
||||
for (const DofComponent component : layout.components_per_node) {
|
||||
const std::size_t component_index = static_cast<std::size_t>(component);
|
||||
if (node >= full_dof_count_ / kDofsPerNode ||
|
||||
component_index >= kDofsPerNode) {
|
||||
if (node >= full_dof_count_ / ComponentsPerNode() ||
|
||||
component_index >= ComponentsPerNode()) {
|
||||
return Result<std::vector<std::size_t>>::Failure(DofFailure(
|
||||
"invalid-element-dof-layout", {},
|
||||
layout.source_id.source_label_text,
|
||||
@@ -510,7 +536,8 @@ Result<std::vector<std::size_t>> DofManager::ElementScatter(
|
||||
"DOF range."));
|
||||
}
|
||||
const std::size_t full_dof =
|
||||
static_cast<std::size_t>(node) * kDofsPerNode + component_index;
|
||||
static_cast<std::size_t>(node) * ComponentsPerNode() +
|
||||
component_index;
|
||||
if (std::find(scatter.begin(), scatter.end(), full_dof) !=
|
||||
scatter.end()) {
|
||||
return Result<std::vector<std::size_t>>::Failure(DofFailure(
|
||||
|
||||
Reference in New Issue
Block a user