feat(result-contract-completion): step 0 — beam-element-end-recovery
This commit is contained in:
@@ -4,8 +4,10 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fesa/fem/gauss_rule.hpp>
|
||||
#include <fesa/fem/line2_shape.hpp>
|
||||
@@ -32,6 +34,20 @@ bool is_positive_finite(const double value) {
|
||||
return std::isfinite(value) && value > 0.0;
|
||||
}
|
||||
|
||||
std::array<double, 6> constitutive_values(
|
||||
const Beam3D2Input& input) {
|
||||
const double shear_modulus =
|
||||
input.material.young / (2.0 * (1.0 + input.material.poisson));
|
||||
return {
|
||||
input.material.young * input.section.area,
|
||||
shear_modulus * input.section.shear_area_y,
|
||||
shear_modulus * input.section.shear_area_z,
|
||||
shear_modulus * input.section.torsion_j,
|
||||
input.material.young * input.section.iy,
|
||||
input.material.young * input.section.iz,
|
||||
};
|
||||
}
|
||||
|
||||
std::optional<BeamKernelResult> validate_properties(
|
||||
const Beam3D2Input& input) {
|
||||
if (!std::isfinite(input.material.young) ||
|
||||
@@ -149,6 +165,34 @@ Matrix12 transform_stiffness(
|
||||
return global;
|
||||
}
|
||||
|
||||
std::array<double, 12> transform_displacement(
|
||||
const Matrix12& transformation,
|
||||
const std::span<const double, 12> global_displacement) {
|
||||
std::array<double, 12> local_displacement{};
|
||||
for (std::size_t row = 0; row < transformation.size(); ++row) {
|
||||
for (std::size_t column = 0;
|
||||
column < transformation[row].size();
|
||||
++column) {
|
||||
local_displacement[row] +=
|
||||
transformation[row][column] * global_displacement[column];
|
||||
}
|
||||
}
|
||||
return local_displacement;
|
||||
}
|
||||
|
||||
std::array<double, 6> evaluate_strain(
|
||||
const StrainMatrix& strain_matrix,
|
||||
const std::array<double, 12>& local_displacement) {
|
||||
std::array<double, 6> strain{};
|
||||
for (std::size_t component = 0; component < strain.size(); ++component) {
|
||||
for (std::size_t dof = 0; dof < local_displacement.size(); ++dof) {
|
||||
strain[component] +=
|
||||
strain_matrix[component][dof] * local_displacement[dof];
|
||||
}
|
||||
}
|
||||
return strain;
|
||||
}
|
||||
|
||||
bool is_finite(const Matrix12& matrix) {
|
||||
for (const auto& row : matrix) {
|
||||
for (const double value : row) {
|
||||
@@ -189,16 +233,8 @@ BeamKernelResult compute_beam3d2(const Beam3D2Input& input) {
|
||||
"Beam kernel requires a representable positive Jacobian.");
|
||||
}
|
||||
|
||||
const double shear_modulus =
|
||||
input.material.young / (2.0 * (1.0 + input.material.poisson));
|
||||
const std::array<double, 6> constitutive{
|
||||
input.material.young * input.section.area,
|
||||
shear_modulus * input.section.shear_area_y,
|
||||
shear_modulus * input.section.shear_area_z,
|
||||
shear_modulus * input.section.torsion_j,
|
||||
input.material.young * input.section.iy,
|
||||
input.material.young * input.section.iz,
|
||||
};
|
||||
const std::array<double, 6> constitutive =
|
||||
constitutive_values(input);
|
||||
for (const double value : constitutive) {
|
||||
if (!is_positive_finite(value)) {
|
||||
return error_result(
|
||||
@@ -241,4 +277,73 @@ BeamKernelResult compute_beam3d2(const Beam3D2Input& input) {
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<BeamSectionResult> recover_beam3d2(
|
||||
const Beam3D2Input& input,
|
||||
const std::span<const double, 12> element_displacement,
|
||||
const std::span<const std::array<double, 2>> recovery_points) {
|
||||
const BeamKernelResult kernel = compute_beam3d2(input);
|
||||
if (!kernel.contribution.has_value()) {
|
||||
const std::string message = kernel.diagnostics.empty()
|
||||
? "Beam recovery requires a valid Beam3D2 input."
|
||||
: kernel.diagnostics.front().message;
|
||||
throw std::invalid_argument{message};
|
||||
}
|
||||
|
||||
const Vec3 axis{
|
||||
input.coordinates[1].x - input.coordinates[0].x,
|
||||
input.coordinates[1].y - input.coordinates[0].y,
|
||||
input.coordinates[1].z - input.coordinates[0].z,
|
||||
};
|
||||
const double jacobian = std::hypot(axis.x, axis.y, axis.z) / 2.0;
|
||||
const Matrix12 transformation =
|
||||
beam_transformation(kernel.contribution->frame);
|
||||
const std::array<double, 12> local_displacement =
|
||||
transform_displacement(transformation, element_displacement);
|
||||
const std::array<double, 6> center_strain = evaluate_strain(
|
||||
strain_matrix(0.0, jacobian),
|
||||
local_displacement);
|
||||
const std::array<double, 6> constitutive =
|
||||
constitutive_values(input);
|
||||
|
||||
std::vector<BeamSectionResult> results;
|
||||
results.reserve(input.node_ids.size());
|
||||
for (std::size_t end = 0; end < input.node_ids.size(); ++end) {
|
||||
const double xi = end == 0 ? -1.0 : 1.0;
|
||||
std::array<double, 6> section_strain = evaluate_strain(
|
||||
strain_matrix(xi, jacobian),
|
||||
local_displacement);
|
||||
section_strain[1] = center_strain[1];
|
||||
section_strain[2] = center_strain[2];
|
||||
|
||||
std::array<double, 6> section_force{};
|
||||
for (std::size_t component = 0;
|
||||
component < section_force.size();
|
||||
++component) {
|
||||
section_force[component] =
|
||||
constitutive[component] * section_strain[component];
|
||||
}
|
||||
|
||||
std::vector<double> sigma_xx;
|
||||
sigma_xx.reserve(recovery_points.size());
|
||||
for (const auto& point : recovery_points) {
|
||||
const double y = point[0];
|
||||
const double z = point[1];
|
||||
sigma_xx.push_back(
|
||||
input.material.young *
|
||||
(section_strain[0] + z * section_strain[4] -
|
||||
y * section_strain[5]));
|
||||
}
|
||||
|
||||
results.push_back({
|
||||
xi,
|
||||
input.node_ids[end],
|
||||
section_strain,
|
||||
section_force,
|
||||
section_force[0] / input.section.area,
|
||||
std::move(sigma_xx),
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace fesa
|
||||
|
||||
Reference in New Issue
Block a user