fix: validate thermal dof layouts
This commit is contained in:
@@ -53,7 +53,9 @@ std::vector<DofComponent> FullNodeComponents() {
|
||||
bool IsThermalSurfaceDof(const int dof) { return dof == 11 || dof == 15; }
|
||||
|
||||
std::size_t ThermalComponentIndex(const ThermalDofComponent component) {
|
||||
return static_cast<std::size_t>(static_cast<int>(component) - 11);
|
||||
const int source_dof = static_cast<int>(component);
|
||||
if (source_dof < 11 || source_dof > 15) return kThermalDofsPerNode;
|
||||
return static_cast<std::size_t>(source_dof - 11);
|
||||
}
|
||||
|
||||
void AppendScatter(std::vector<std::vector<std::size_t>>& columns_by_row,
|
||||
@@ -157,8 +159,9 @@ Result<DofManager> DofManager::CreateThermal(const AnalysisModel& model) {
|
||||
Status DofManager::Build(const AnalysisModel& analysis_model,
|
||||
const ElementView& elements) {
|
||||
if (analysis_model.IsThermal()) {
|
||||
return DofFailure("invalid-dof-profile", {analysis_model.GetDomain().SourcePath(), 0U},
|
||||
"structural", "Structural element layouts cannot build a thermal mapping.");
|
||||
return DofFailure(
|
||||
"invalid-dof-profile", {analysis_model.GetDomain().SourcePath(), 0U},
|
||||
"structural", "Structural element layouts cannot build a thermal mapping.");
|
||||
}
|
||||
return Build(analysis_model, elements,
|
||||
analysis_model.Step().BoundaryConditions());
|
||||
@@ -169,8 +172,9 @@ Status DofManager::Build(const AnalysisModel& analysis_model,
|
||||
const BoundaryConditionView& boundaries) {
|
||||
std::vector<ElementDofLayout> layouts;
|
||||
if (analysis_model.IsThermal()) {
|
||||
return DofFailure("invalid-dof-profile", {analysis_model.GetDomain().SourcePath(), 0U},
|
||||
"structural", "Structural element layouts cannot build a thermal mapping.");
|
||||
return DofFailure(
|
||||
"invalid-dof-profile", {analysis_model.GetDomain().SourcePath(), 0U},
|
||||
"structural", "Structural element layouts cannot build a thermal mapping.");
|
||||
}
|
||||
layouts.reserve(elements.size());
|
||||
for (const auto& element : elements) {
|
||||
@@ -183,13 +187,16 @@ Status DofManager::BuildThermal(
|
||||
const AnalysisModel& analysis_model,
|
||||
const std::vector<ThermalElementDofLayout>& layouts) {
|
||||
if (!analysis_model.IsThermal() || analysis_model.ThermalStep() == nullptr) {
|
||||
return DofFailure("invalid-dof-profile", {analysis_model.GetDomain().SourcePath(), 0U},
|
||||
"thermal", "Thermal layouts require a thermal AnalysisModel.");
|
||||
return DofFailure(
|
||||
"invalid-dof-profile", {analysis_model.GetDomain().SourcePath(), 0U},
|
||||
"thermal", "Thermal layouts require a thermal AnalysisModel.");
|
||||
}
|
||||
const Domain& domain = analysis_model.GetDomain();
|
||||
if (layouts.size() != analysis_model.ActiveThermalElements().size()) {
|
||||
return DofFailure("invalid-element-layout-order", {domain.SourcePath(), 0U},
|
||||
std::to_string(layouts.size()), "Thermal layouts must match the active DS4 inventory.");
|
||||
return DofFailure(
|
||||
"invalid-element-layout-order", {domain.SourcePath(), 0U},
|
||||
std::to_string(layouts.size()),
|
||||
"Thermal layouts must match the active DS4 inventory.");
|
||||
}
|
||||
DofManager candidate;
|
||||
candidate.profile_ = DofProfile::kThermal;
|
||||
@@ -198,8 +205,9 @@ Status DofManager::BuildThermal(
|
||||
++row) {
|
||||
const EntityIndex node = analysis_model.ActiveThermalNodes()[row];
|
||||
if (node >= candidate.thermal_node_rows_.size()) {
|
||||
return DofFailure("invalid-thermal-node", {domain.SourcePath(), 0U},
|
||||
std::to_string(node), "Active thermal node is outside Domain nodes.");
|
||||
return DofFailure(
|
||||
"invalid-thermal-node", {domain.SourcePath(), 0U},
|
||||
std::to_string(node), "Active thermal node is outside Domain nodes.");
|
||||
}
|
||||
candidate.thermal_node_rows_[node] = row;
|
||||
}
|
||||
@@ -209,8 +217,9 @@ Status DofManager::BuildThermal(
|
||||
for (std::size_t index = 0U; index < layouts.size(); ++index) {
|
||||
const auto& definition = domain.ThermalElements()[index];
|
||||
if (!SameSourceIdentity(layouts[index].source_id, definition.SourceId())) {
|
||||
return DofFailure("invalid-element-layout-order", {domain.SourcePath(), 0U},
|
||||
std::to_string(index), "Thermal layout identity changed source order.");
|
||||
return DofFailure(
|
||||
"invalid-element-layout-order", {domain.SourcePath(), 0U},
|
||||
std::to_string(index), "Thermal layout identity changed source order.");
|
||||
}
|
||||
for (std::size_t node = 0U; node < layouts[index].node_indices.size();
|
||||
++node) {
|
||||
@@ -225,9 +234,10 @@ Status DofManager::BuildThermal(
|
||||
candidate.element_scatters_.push_back(scatter.Value());
|
||||
}
|
||||
std::map<std::size_t, double> effective;
|
||||
const auto apply = [&candidate, &effective](
|
||||
const std::vector<ThermalBoundaryConditionDefinition>& boundaries,
|
||||
const bool overrides) -> Status {
|
||||
const auto apply =
|
||||
[&candidate, &effective](
|
||||
const std::vector<ThermalBoundaryConditionDefinition>& boundaries,
|
||||
const bool overrides) -> Status {
|
||||
for (const auto& boundary : boundaries) {
|
||||
if (!IsThermalSurfaceDof(boundary.dof) || !std::isfinite(boundary.value)) {
|
||||
return DofFailure("invalid-thermal-boundary", boundary.location, "BOUNDARY",
|
||||
@@ -521,6 +531,15 @@ Result<std::vector<std::size_t>> DofManager::ThermalElementScatter(
|
||||
"Thermal layouts require a thermal mapping."));
|
||||
}
|
||||
std::array<bool, kThermalDofsPerNode> components{};
|
||||
const std::array<ThermalDofComponent, kThermalDofsPerNode> canonical{
|
||||
{ThermalDofComponent::kBottom, ThermalDofComponent::kLower,
|
||||
ThermalDofComponent::kMiddle, ThermalDofComponent::kUpper,
|
||||
ThermalDofComponent::kTop}};
|
||||
if (layout.components != canonical) {
|
||||
return Result<std::vector<std::size_t>>::Failure(DofFailure(
|
||||
"invalid-thermal-element-layout", {}, layout.source_id.source_label_text,
|
||||
"Thermal layouts must preserve canonical bottom-to-top stations."));
|
||||
}
|
||||
for (const auto component : layout.components) {
|
||||
const std::size_t index = ThermalComponentIndex(component);
|
||||
if (index >= components.size() || components[index]) {
|
||||
@@ -543,11 +562,16 @@ Result<std::vector<std::size_t>> DofManager::ThermalElementScatter(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (std::adjacent_find(layout.node_indices.begin(), layout.node_indices.end()) !=
|
||||
layout.node_indices.end()) {
|
||||
return Result<std::vector<std::size_t>>::Failure(DofFailure(
|
||||
"duplicate-element-dof", {}, layout.source_id.source_label_text,
|
||||
"A thermal layout must not repeat a node."));
|
||||
for (std::size_t index = 0U; index < layout.node_indices.size(); ++index) {
|
||||
if (std::find(layout.node_indices.begin(),
|
||||
layout.node_indices.begin() +
|
||||
static_cast<std::ptrdiff_t>(index),
|
||||
layout.node_indices[index]) !=
|
||||
layout.node_indices.begin() + static_cast<std::ptrdiff_t>(index)) {
|
||||
return Result<std::vector<std::size_t>>::Failure(DofFailure(
|
||||
"duplicate-element-dof", {}, layout.source_id.source_label_text,
|
||||
"A thermal layout must not repeat a node."));
|
||||
}
|
||||
}
|
||||
return Result<std::vector<std::size_t>>::Success(std::move(scatter));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user