Integrate Refactor solver sources and dual MSVC CMake builds
This commit is contained in:
@@ -6,12 +6,18 @@
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "fesa/elements/finite_rotation.h"
|
||||
#include "elements/nonlinear_mitc4_configuration_internal.h"
|
||||
#include "math/dense_blas_internal.h"
|
||||
#include "math/jet_arithmetic.h"
|
||||
#include "math/jet_linear_solve.h"
|
||||
#include "math/finite_values.h"
|
||||
#include "math/vector3_operations.h"
|
||||
#include "elements/shell_kernel_values.h"
|
||||
|
||||
namespace fesa {
|
||||
|
||||
@@ -40,6 +46,15 @@ nonlinear_mitc4_internal::ConfigurationSnapshot::Read(
|
||||
|
||||
namespace {
|
||||
|
||||
using shell_kernel_internal::Failure;
|
||||
using shell_kernel_internal::FrameComponent;
|
||||
using shell_kernel_internal::LocalEngineeringComponents;
|
||||
using shell_kernel_internal::FrameMatrix;
|
||||
using shell_kernel_internal::ElementIdentity;
|
||||
using math_internal::DerivativeSum;
|
||||
using math_internal::WeightedSum;
|
||||
using math_internal::IsFinite;
|
||||
|
||||
constexpr std::size_t kNodeCount = 4U;
|
||||
constexpr double kFrameTolerance = 1.0e-12;
|
||||
constexpr double kDirectorOppositionTolerance = 1.0e-8;
|
||||
@@ -53,7 +68,7 @@ struct Geometry {
|
||||
std::array<Vector3, 3> reference_covariant;
|
||||
std::array<Vector3, 3> current_covariant;
|
||||
std::array<Vector3, 3> covariant_increment;
|
||||
std::array<Vector3, 3> reciprocal;
|
||||
std::optional<dense_blas_internal::DenseFactor> reference_factor;
|
||||
Mitc4LocalFrame local_frame;
|
||||
double reference_jacobian;
|
||||
};
|
||||
@@ -64,61 +79,6 @@ struct PointEvaluation {
|
||||
EngineeringStress stress;
|
||||
};
|
||||
|
||||
/// @brief Builds one deterministic structured nonlinear-shell failure.
|
||||
template <class T>
|
||||
Result<T> Failure(const std::string& code, const SourceLocation& location,
|
||||
const std::string& identity, std::string message) {
|
||||
return Result<T>::Failure(Status::Failure(
|
||||
FailureCategory::kModel, {{Severity::kError, code, location, "*ELEMENT",
|
||||
identity, std::move(message)}}));
|
||||
}
|
||||
|
||||
/// @brief Builds the stable source label concatenation used by diagnostics.
|
||||
std::string ElementIdentity(const std::array<const Node*, kNodeCount>& nodes) {
|
||||
std::string identity;
|
||||
for (const Node* node : nodes) {
|
||||
if (node == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (!identity.empty()) {
|
||||
identity += "-";
|
||||
}
|
||||
identity += node->source_id.source_label_text;
|
||||
}
|
||||
return identity;
|
||||
}
|
||||
|
||||
/// @brief Forms a weighted vector sum in source-node order.
|
||||
Vector3 WeightedSum(const std::array<double, kNodeCount>& weights,
|
||||
const std::array<Vector3, kNodeCount>& values) {
|
||||
Vector3 result{};
|
||||
for (std::size_t node = 0U; node < kNodeCount; ++node) {
|
||||
result = result + weights[node] * values[node];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Forms a stable derivative sum after cancelling the constant term.
|
||||
Vector3 DerivativeSum(const std::array<double, kNodeCount>& derivatives,
|
||||
const std::array<Vector3, kNodeCount>& values) {
|
||||
std::array<Vector3, kNodeCount> relative{};
|
||||
for (std::size_t node = 0U; node < kNodeCount; ++node) {
|
||||
relative[node] = values[node] - values[0U];
|
||||
}
|
||||
return WeightedSum(derivatives, relative);
|
||||
}
|
||||
|
||||
/// @brief Returns a frame matrix whose columns are a, b and the director.
|
||||
Matrix FrameMatrix(const ShellNodeInitialFrame& frame) {
|
||||
Matrix result{3U, 3U};
|
||||
for (std::size_t row = 0U; row < 3U; ++row) {
|
||||
result(row, 0U) = frame.tangent_a[row];
|
||||
result(row, 1U) = frame.tangent_b[row];
|
||||
result(row, 2U) = frame.director[row];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Checks every scalar in a tensor before recovery commits it.
|
||||
bool IsFinite(const Tensor& tensor) {
|
||||
for (const auto& row : tensor) {
|
||||
@@ -131,13 +91,6 @@ bool IsFinite(const Tensor& tensor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Checks every scalar in one fixed-size engineering quantity.
|
||||
template <std::size_t N>
|
||||
bool IsFinite(const std::array<double, N>& values) {
|
||||
return std::all_of(values.begin(), values.end(),
|
||||
[](const double value) { return std::isfinite(value); });
|
||||
}
|
||||
|
||||
/// @brief Evaluates a determinant from covariant basis columns.
|
||||
double Determinant(const std::array<Vector3, 3>& covariant) {
|
||||
return covariant[0U].Dot(covariant[1U].Cross(covariant[2U]));
|
||||
@@ -256,20 +209,24 @@ bool EvaluateGeometry(const std::array<Vector3, kNodeCount>& coordinates,
|
||||
return false;
|
||||
}
|
||||
|
||||
geometry.reciprocal[0U] =
|
||||
geometry.reference_covariant[1U].Cross(geometry.reference_covariant[2U]) /
|
||||
geometry.reference_jacobian;
|
||||
geometry.reciprocal[1U] =
|
||||
geometry.reference_covariant[2U].Cross(geometry.reference_covariant[0U]) /
|
||||
geometry.reference_jacobian;
|
||||
geometry.reciprocal[2U] =
|
||||
geometry.reference_covariant[0U].Cross(geometry.reference_covariant[1U]) /
|
||||
geometry.reference_jacobian;
|
||||
if (!geometry.reciprocal[0U].IsFinite() ||
|
||||
!geometry.reciprocal[1U].IsFinite() ||
|
||||
!geometry.reciprocal[2U].IsFinite()) {
|
||||
return false;
|
||||
// Retain the old unscaled cross-product finite gate before factor actions.
|
||||
for (std::size_t alpha = 0; alpha < 3; ++alpha)
|
||||
if (!geometry.reference_covariant[(alpha+1)%3].Cross(
|
||||
geometry.reference_covariant[(alpha+2)%3]).IsFinite()) return false;
|
||||
Matrix basis{3, 3};
|
||||
for (std::size_t row = 0; row < 3; ++row)
|
||||
for (std::size_t alpha = 0; alpha < 3; ++alpha)
|
||||
basis(row, alpha) = geometry.reference_covariant[alpha][row];
|
||||
auto factor = dense_blas_internal::DenseFactor::Lu(basis);
|
||||
if (!factor.HasValue()) return false;
|
||||
// Stream the former reciprocal finite gate without retaining an inverse.
|
||||
Matrix rhs{3, 1};
|
||||
for (std::size_t column = 0; column < 3; ++column) {
|
||||
if (column != 0) rhs(column-1, 0) = 0;
|
||||
rhs(column, 0) = 1;
|
||||
if (!factor.Value().Solve(rhs).HasValue()) return false;
|
||||
}
|
||||
geometry.reference_factor = std::move(factor.Value());
|
||||
return MakeLocalFrame(reference_xi, reference_eta, initial_director,
|
||||
geometry.local_frame);
|
||||
}
|
||||
@@ -293,47 +250,27 @@ Tensor DirectStrain(const Geometry& geometry) {
|
||||
}
|
||||
|
||||
/// @brief Reconstructs a fixed-reference Cartesian strain from covariant data.
|
||||
Tensor CartesianStrain(const Tensor& covariant,
|
||||
const std::array<Vector3, 3>& reciprocal) {
|
||||
Tensor CartesianStrain(const Tensor& covariant, const Geometry& reference) {
|
||||
Matrix rhs{3, 3};
|
||||
for (std::size_t row = 0; row < 3; ++row)
|
||||
for (std::size_t column = 0; column < 3; ++column)
|
||||
rhs(row, column) = covariant[row][column];
|
||||
const auto right = reference.reference_factor->SolveRight(rhs);
|
||||
Tensor cartesian{};
|
||||
for (std::size_t row = 0U; row < 3U; ++row) {
|
||||
for (std::size_t column = 0U; column < 3U; ++column) {
|
||||
for (std::size_t first = 0U; first < 3U; ++first) {
|
||||
for (std::size_t second = 0U; second < 3U; ++second) {
|
||||
cartesian[row][column] += covariant[first][second] *
|
||||
reciprocal[first][row] *
|
||||
reciprocal[second][column];
|
||||
}
|
||||
}
|
||||
if (right.HasValue()) {
|
||||
const auto left = reference.reference_factor->Solve(right.Value(), true);
|
||||
if (left.HasValue()) {
|
||||
for (std::size_t row = 0; row < 3; ++row)
|
||||
for (std::size_t column = 0; column < 3; ++column)
|
||||
cartesian[row][column] = left.Value()(row, column);
|
||||
return cartesian;
|
||||
}
|
||||
}
|
||||
for (auto& row : cartesian)
|
||||
row.fill(std::numeric_limits<double>::quiet_NaN());
|
||||
return cartesian;
|
||||
}
|
||||
|
||||
/// @brief Evaluates a tensor component in a fixed local reference frame.
|
||||
double FrameComponent(const Vector3& left, const Tensor& tensor,
|
||||
const Vector3& right) {
|
||||
double value = 0.0;
|
||||
for (std::size_t row = 0U; row < 3U; ++row) {
|
||||
for (std::size_t column = 0U; column < 3U; ++column) {
|
||||
value += left[row] * tensor[row][column] * right[column];
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// @brief Converts fixed-reference Cartesian strain to engineering components.
|
||||
EngineeringStrain LocalEngineering(const Tensor& tensor,
|
||||
const Mitc4LocalFrame& frame) {
|
||||
const Vector3 e1{frame.e1};
|
||||
const Vector3 e2{frame.e2};
|
||||
const Vector3 e3{frame.e3};
|
||||
return {FrameComponent(e1, tensor, e1), FrameComponent(e2, tensor, e2),
|
||||
2.0 * FrameComponent(e1, tensor, e2),
|
||||
2.0 * FrameComponent(e1, tensor, e3),
|
||||
2.0 * FrameComponent(e2, tensor, e3)};
|
||||
}
|
||||
|
||||
/// @brief Applies the approved homogeneous plane-stress plus shear law.
|
||||
EngineeringStress Stress(const EngineeringStrain& strain, const double youngs,
|
||||
const double poisson) {
|
||||
@@ -386,8 +323,8 @@ PointStatus EvaluatePoint(const std::array<Vector3, kNodeCount>& coordinates,
|
||||
weights.eta_zeta[1U] * tying_samples[3U][1U][2U];
|
||||
covariant[2U][1U] = covariant[1U][2U];
|
||||
const Tensor cartesian =
|
||||
CartesianStrain(covariant, point.geometry.reciprocal);
|
||||
point.strain = LocalEngineering(cartesian, point.geometry.local_frame);
|
||||
CartesianStrain(covariant, point.geometry);
|
||||
point.strain = LocalEngineeringComponents(cartesian, point.geometry.local_frame);
|
||||
point.stress = Stress(point.strain, youngs, poisson);
|
||||
return IsFinite(covariant) && IsFinite(cartesian) && IsFinite(point.strain) &&
|
||||
IsFinite(point.stress)
|
||||
@@ -890,27 +827,12 @@ JetMatrix3 Skew(const JetVector3& value) {
|
||||
|
||||
/// @brief Multiplies two three-by-three Jet matrices.
|
||||
JetMatrix3 Multiply(const JetMatrix3& left, const JetMatrix3& right) {
|
||||
JetMatrix3 result = ConstantZeroMatrix();
|
||||
for (std::size_t row = 0U; row < 3U; ++row) {
|
||||
for (std::size_t column = 0U; column < 3U; ++column) {
|
||||
for (std::size_t index = 0U; index < 3U; ++index) {
|
||||
result[row][column] =
|
||||
result[row][column] + left[row][index] * right[index][column];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return math_internal::MultiplyJetMatrix(left, right, Constant);
|
||||
}
|
||||
|
||||
/// @brief Multiplies a Jet matrix by a Jet vector.
|
||||
JetVector3 Multiply(const JetMatrix3& matrix, const JetVector3& vector) {
|
||||
JetVector3 result{Constant(0.0), Constant(0.0), Constant(0.0)};
|
||||
for (std::size_t row = 0U; row < 3U; ++row) {
|
||||
for (std::size_t column = 0U; column < 3U; ++column) {
|
||||
result[row] = result[row] + matrix[row][column] * vector[column];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return math_internal::MultiplyJetMatrixVector(matrix, vector, Constant);
|
||||
}
|
||||
|
||||
/// @brief Transposes a three-by-three Jet matrix.
|
||||
@@ -957,38 +879,28 @@ JetMatrix3 Add(const JetMatrix3& left, const JetMatrix3& right) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Computes the analytic three-by-three inverse through its adjugate.
|
||||
JetMatrix3 Inverse(const JetMatrix3& matrix) {
|
||||
JetMatrix3 cofactor{};
|
||||
cofactor[0U][0U] =
|
||||
matrix[1U][1U] * matrix[2U][2U] - matrix[1U][2U] * matrix[2U][1U];
|
||||
cofactor[0U][1U] =
|
||||
matrix[1U][2U] * matrix[2U][0U] - matrix[1U][0U] * matrix[2U][2U];
|
||||
cofactor[0U][2U] =
|
||||
matrix[1U][0U] * matrix[2U][1U] - matrix[1U][1U] * matrix[2U][0U];
|
||||
cofactor[1U][0U] =
|
||||
matrix[0U][2U] * matrix[2U][1U] - matrix[0U][1U] * matrix[2U][2U];
|
||||
cofactor[1U][1U] =
|
||||
matrix[0U][0U] * matrix[2U][2U] - matrix[0U][2U] * matrix[2U][0U];
|
||||
cofactor[1U][2U] =
|
||||
matrix[0U][1U] * matrix[2U][0U] - matrix[0U][0U] * matrix[2U][1U];
|
||||
cofactor[2U][0U] =
|
||||
matrix[0U][1U] * matrix[1U][2U] - matrix[0U][2U] * matrix[1U][1U];
|
||||
cofactor[2U][1U] =
|
||||
matrix[0U][2U] * matrix[1U][0U] - matrix[0U][0U] * matrix[1U][2U];
|
||||
cofactor[2U][2U] =
|
||||
matrix[0U][0U] * matrix[1U][1U] - matrix[0U][1U] * matrix[1U][0U];
|
||||
const Jet determinant = matrix[0U][0U] * cofactor[0U][0U] +
|
||||
matrix[0U][1U] * cofactor[0U][1U] +
|
||||
matrix[0U][2U] * cofactor[0U][2U];
|
||||
JetMatrix3 result{};
|
||||
const Jet inverse_determinant = Reciprocal(determinant);
|
||||
for (std::size_t row = 0U; row < 3U; ++row) {
|
||||
for (std::size_t column = 0U; column < 3U; ++column) {
|
||||
result[row][column] = cofactor[column][row] * inverse_determinant;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
/// @brief Reads shell variations without conflating directional third order.
|
||||
double ReadChannel(const Jet& jet, std::size_t degree, std::size_t channel) {
|
||||
if (degree == 0) return jet.value;
|
||||
if (degree == 1) return channel < kGlobalDofCount ? jet.first[channel]
|
||||
: jet.directional_first;
|
||||
if (degree == 3) return jet.mixed_second[channel];
|
||||
if (channel < kHessianSize) return jet.second.ReadData()[channel];
|
||||
if (channel == kHessianSize) return jet.directional_second;
|
||||
return jet.mixed_first[channel - kHessianSize - 1];
|
||||
}
|
||||
void WriteChannel(Jet& jet, std::size_t degree, std::size_t channel,
|
||||
double value) {
|
||||
if (degree == 0) { jet.value = value; return; }
|
||||
// A null Hessian is not constant provenance, including zero first seeds.
|
||||
jet.constant_derivatives = false;
|
||||
if (degree == 1) {
|
||||
if (channel < kGlobalDofCount) jet.first[channel] = value;
|
||||
else jet.directional_first = value;
|
||||
} else if (degree == 3) jet.mixed_second[channel] = value;
|
||||
else if (channel < kHessianSize) jet.second.OverwriteData()[channel] = value;
|
||||
else if (channel == kHessianSize) jet.directional_second = value;
|
||||
else jet.mixed_first[channel - kHessianSize - 1] = value;
|
||||
}
|
||||
|
||||
/// @brief Evaluates Rodrigues' map with an analytic near-zero series branch.
|
||||
@@ -1119,19 +1031,32 @@ JetTensor DirectStrain(const std::array<JetVector3, 3>& increment,
|
||||
/// @brief Reconstructs a fixed-reference Cartesian Jet strain tensor.
|
||||
JetTensor CartesianStrain(const JetTensor& covariant,
|
||||
const Geometry& reference) {
|
||||
JetTensor result{};
|
||||
for (std::size_t row = 0U; row < 3U; ++row) {
|
||||
for (std::size_t column = 0U; column < 3U; ++column) {
|
||||
for (std::size_t first = 0U; first < 3U; ++first) {
|
||||
for (std::size_t second = 0U; second < 3U; ++second) {
|
||||
result[row][column] =
|
||||
result[row][column] + reference.reciprocal[first][row] *
|
||||
reference.reciprocal[second][column] *
|
||||
covariant[first][second];
|
||||
}
|
||||
}
|
||||
// E_cart = B^-T E_cov B^-1. First solve each row against B, then each
|
||||
// column against B^T, carrying every independent Jet channel unchanged.
|
||||
const std::array<std::size_t, 4> channels{
|
||||
1, kGlobalDofCount+1, kHessianSize+1+kGlobalDofCount, kGlobalDofCount};
|
||||
JetTensor right{}, result{};
|
||||
for (std::size_t row = 0; row < 3; ++row) {
|
||||
if (!math_internal::SolveConstantJetAction(
|
||||
covariant[row], *reference.reference_factor, true, channels,
|
||||
Constant, ReadChannel, WriteChannel, right[row])) {
|
||||
for (auto& entry : result)
|
||||
entry.fill(Constant(std::numeric_limits<double>::quiet_NaN()));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (std::size_t column = 0; column < 3; ++column) {
|
||||
const JetVector3 rhs{right[0][column],right[1][column],right[2][column]};
|
||||
JetVector3 action{};
|
||||
if (!math_internal::SolveConstantJetAction(
|
||||
rhs, *reference.reference_factor, true, channels,
|
||||
Constant, ReadChannel, WriteChannel, action)) {
|
||||
for (auto& entry : result)
|
||||
entry.fill(Constant(std::numeric_limits<double>::quiet_NaN()));
|
||||
return result;
|
||||
}
|
||||
for (std::size_t row = 0; row < 3; ++row) result[row][column] = action[row];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1235,7 +1160,29 @@ Jet PhysicalEnergy(const std::array<Vector3, kNodeCount>& coordinates,
|
||||
JetMatrix3 PolarRotation(const JetMatrix3& deformation) {
|
||||
JetMatrix3 result = deformation;
|
||||
for (std::size_t iteration = 0U; iteration < 12U; ++iteration) {
|
||||
result = Scale(0.5, Add(result, Transpose(Inverse(result))));
|
||||
const JetMatrix3 coefficients = Transpose(result);
|
||||
Matrix primal{3, 3};
|
||||
for (std::size_t row = 0; row < 3; ++row)
|
||||
for (std::size_t column = 0; column < 3; ++column)
|
||||
primal(row, column) = coefficients[row][column].value;
|
||||
const auto factor = dense_blas_internal::DenseFactor::Lu(primal);
|
||||
JetMatrix3 candidate{};
|
||||
for (std::size_t column = 0; column < 3; ++column) {
|
||||
JetVector3 rhs{Constant(0), Constant(0), Constant(0)}, action{};
|
||||
rhs[column] = Constant(1);
|
||||
if (!factor.HasValue() || !math_internal::SolveJetAction(
|
||||
coefficients, rhs, factor.Value(),
|
||||
{1, kGlobalDofCount + 1, kHessianSize + 1 + kGlobalDofCount,
|
||||
kGlobalDofCount}, Constant, ReadChannel, WriteChannel, action)) {
|
||||
for (auto& row : candidate)
|
||||
row.fill(Constant(std::numeric_limits<double>::quiet_NaN()));
|
||||
return candidate;
|
||||
}
|
||||
for (std::size_t row = 0; row < 3; ++row)
|
||||
candidate[row][column] = 0.5 * (result[row][column] + action[row]);
|
||||
}
|
||||
// All actions used the previous snapshot; never a partial next iterate.
|
||||
result = std::move(candidate);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1297,14 +1244,19 @@ Jet DrillingEnergy(const std::array<Vector3, kNodeCount>& coordinates,
|
||||
const auto current =
|
||||
CovariantIncrement(initial_directors, trial, thickness, 0.0, 0.0, 0.0);
|
||||
JetMatrix3 deformation = Identity();
|
||||
for (std::size_t row = 0U; row < 3U; ++row) {
|
||||
for (std::size_t column = 0U; column < 3U; ++column) {
|
||||
for (std::size_t alpha = 0U; alpha < 3U; ++alpha) {
|
||||
deformation[row][column] =
|
||||
deformation[row][column] +
|
||||
current[alpha][row] * reference.reciprocal[alpha][column];
|
||||
}
|
||||
const std::array<std::size_t, 4> channels{
|
||||
1, kGlobalDofCount+1, kHessianSize+1+kGlobalDofCount, kGlobalDofCount};
|
||||
for (std::size_t row = 0; row < 3; ++row) {
|
||||
const JetVector3 rhs{current[0][row],current[1][row],current[2][row]};
|
||||
JetVector3 action{};
|
||||
if (!math_internal::SolveConstantJetAction(
|
||||
rhs, *reference.reference_factor, true, channels,
|
||||
Constant, ReadChannel, WriteChannel, action)) {
|
||||
valid = false;
|
||||
return {};
|
||||
}
|
||||
for (std::size_t column = 0; column < 3; ++column)
|
||||
deformation[row][column] = deformation[row][column] + action[column];
|
||||
}
|
||||
const JetMatrix3 element_rotation = PolarRotation(deformation);
|
||||
Jet energy{};
|
||||
|
||||
Reference in New Issue
Block a user