feat(cpp-object-oriented-modular-refactoring): step 14 - runtime-element-factory
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -77,6 +78,29 @@ Result<EulerBeam3D> ModelFailure(const std::string& code,
|
||||
{{Severity::kError, code, location, "*ELEMENT", identity, message}}));
|
||||
}
|
||||
|
||||
/// @brief Creates a structured failure at the runtime element boundary.
|
||||
template <class T>
|
||||
Result<T> RuntimeFailure(const SourceLocation& location,
|
||||
const SourceEntityId& source_id,
|
||||
const std::string& message) {
|
||||
return Result<T>::Failure(
|
||||
Status::Failure(FailureCategory::kModel,
|
||||
{{Severity::kError, "invalid-runtime-element", location,
|
||||
"*ELEMENT", source_id.source_label_text, message}}));
|
||||
}
|
||||
|
||||
/// @brief Reports whether every fixed-size recovery component is finite.
|
||||
template <class T, std::size_t Size>
|
||||
bool IsFinite(const std::array<T, Size>& values) {
|
||||
return std::all_of(values.begin(), values.end(), [](const auto& value) {
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
return std::isfinite(value);
|
||||
} else {
|
||||
return IsFinite(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Repeats the local-axis rotation in stable nodal translation and
|
||||
/// rotation blocks.
|
||||
Matrix Transformation(const std::array<double, 9>& rotation) {
|
||||
@@ -428,7 +452,7 @@ Vector EulerBeam3D::LocalEquivalentLoad(
|
||||
return equivalent;
|
||||
}
|
||||
|
||||
BeamRecovery EulerBeam3D::Recover(
|
||||
BeamRecovery EulerBeam3D::RecoverBeam(
|
||||
const Vector& global_element_displacement) const {
|
||||
const Matrix transform = Transformation(rotation_);
|
||||
const Vector local_displacement =
|
||||
@@ -484,6 +508,105 @@ BeamRecovery EulerBeam3D::Recover(
|
||||
return recovery;
|
||||
}
|
||||
|
||||
const ElementDofLayout& EulerBeam3D::DofLayout() const noexcept {
|
||||
return dof_layout_;
|
||||
}
|
||||
|
||||
Result<ElementStiffnessContribution> EulerBeam3D::ComputeStiffness() const {
|
||||
if (dof_layout_.node_indices.size() != 2U ||
|
||||
dof_layout_.components_per_node.size() != 6U) {
|
||||
return RuntimeFailure<ElementStiffnessContribution>(
|
||||
runtime_location_, dof_layout_.source_id,
|
||||
"B33 runtime stiffness requires a bound two-node six-DOF layout.");
|
||||
}
|
||||
try {
|
||||
return Result<ElementStiffnessContribution>::Success(
|
||||
{dof_layout_, GlobalStiffness()});
|
||||
} catch (const std::exception& error) {
|
||||
return RuntimeFailure<ElementStiffnessContribution>(
|
||||
runtime_location_, dof_layout_.source_id, error.what());
|
||||
}
|
||||
}
|
||||
|
||||
Result<ElementResultBundle> EulerBeam3D::Recover(
|
||||
const Vector& element_displacement) const {
|
||||
if (dof_layout_.node_indices.size() != 2U ||
|
||||
dof_layout_.components_per_node.size() != 6U ||
|
||||
node_source_ids_.size() != 2U ||
|
||||
element_displacement.Size() != kElementDofCount) {
|
||||
return RuntimeFailure<ElementResultBundle>(
|
||||
runtime_location_, dof_layout_.source_id,
|
||||
"B33 runtime recovery requires a bound two-node layout and 12 DOFs.");
|
||||
}
|
||||
for (std::size_t dof = 0U; dof < element_displacement.Size(); ++dof) {
|
||||
if (!std::isfinite(element_displacement[dof])) {
|
||||
return RuntimeFailure<ElementResultBundle>(
|
||||
runtime_location_, dof_layout_.source_id,
|
||||
"B33 runtime recovery displacement must be finite.");
|
||||
}
|
||||
}
|
||||
|
||||
BeamRecovery recovered{};
|
||||
try {
|
||||
recovered = RecoverBeam(element_displacement);
|
||||
} catch (const std::exception& error) {
|
||||
return RuntimeFailure<ElementResultBundle>(
|
||||
runtime_location_, dof_layout_.source_id, error.what());
|
||||
}
|
||||
|
||||
BeamElementResultRows rows{};
|
||||
rows.endpoint_rows.reserve(2U);
|
||||
rows.gauss_rows.reserve(2U);
|
||||
rows.stress_rows.reserve(recovered.stress_points.size());
|
||||
for (std::size_t endpoint = 0U; endpoint < 2U; ++endpoint) {
|
||||
if (!IsFinite(recovered.equilibrium_end_actions[endpoint]) ||
|
||||
!IsFinite(recovered.endpoint_section_resultants[endpoint])) {
|
||||
return RuntimeFailure<ElementResultBundle>(
|
||||
runtime_location_, dof_layout_.source_id,
|
||||
"B33 endpoint recovery values must be finite.");
|
||||
}
|
||||
rows.endpoint_rows.push_back(
|
||||
{element_index_, static_cast<int>(endpoint), node_source_ids_[endpoint],
|
||||
recovered.equilibrium_end_actions[endpoint],
|
||||
recovered.endpoint_section_resultants[endpoint]});
|
||||
}
|
||||
for (std::size_t gauss = 0U; gauss < 2U; ++gauss) {
|
||||
if (!IsFinite(recovered.gauss_generalized_strains[gauss]) ||
|
||||
!IsFinite(recovered.gauss_generalized_resultants[gauss])) {
|
||||
return RuntimeFailure<ElementResultBundle>(
|
||||
runtime_location_, dof_layout_.source_id,
|
||||
"B33 Gauss recovery values must be finite.");
|
||||
}
|
||||
rows.gauss_rows.push_back({element_index_, static_cast<int>(gauss + 1U),
|
||||
recovered.gauss_generalized_strains[gauss],
|
||||
recovered.gauss_generalized_resultants[gauss]});
|
||||
}
|
||||
for (const auto& point : recovered.stress_points) {
|
||||
if ((point.gauss_point != 1 && point.gauss_point != 2) ||
|
||||
!std::isfinite(point.x1) || !std::isfinite(point.x2) ||
|
||||
!std::isfinite(point.s11)) {
|
||||
return RuntimeFailure<ElementResultBundle>(
|
||||
runtime_location_, dof_layout_.source_id,
|
||||
"B33 stress recovery identity and values must be finite.");
|
||||
}
|
||||
rows.stress_rows.push_back({element_index_, point.gauss_point,
|
||||
point.section_point, point.x1, point.x2,
|
||||
point.s11, point.source});
|
||||
}
|
||||
return Result<ElementResultBundle>::Success(
|
||||
{dof_layout_.source_id, std::move(rows)});
|
||||
}
|
||||
|
||||
void EulerBeam3D::BindRuntime(ElementDofLayout layout,
|
||||
const EntityIndex element_index,
|
||||
std::vector<SourceEntityId> node_source_ids,
|
||||
SourceLocation location) {
|
||||
dof_layout_ = std::move(layout);
|
||||
element_index_ = element_index;
|
||||
node_source_ids_ = std::move(node_source_ids);
|
||||
runtime_location_ = std::move(location);
|
||||
}
|
||||
|
||||
EulerBeam3D::EulerBeam3D(double length, double youngs_modulus,
|
||||
double shear_modulus, double area, double iy,
|
||||
double iz, double torsional_constant,
|
||||
|
||||
Reference in New Issue
Block a user