Integrate Refactor solver sources and dual MSVC CMake builds

This commit is contained in:
KOKO\Mimi
2026-10-18 02:10:51 +09:00
parent 7ee32e5837
commit 12d51480de
218 changed files with 17842 additions and 9689 deletions
+133 -181
View File
@@ -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{};