Connect MITC4 drilling evidence across analysis procedures

This commit is contained in:
KOKO\Mimi
2026-10-20 09:21:39 +09:00
parent 294ffbf8a1
commit c6188b3ad7
30 changed files with 763 additions and 28 deletions
+2 -1
View File
@@ -48,7 +48,8 @@ Status CommitRecoveryCandidate(RecoveryCandidate candidate,
!candidate.shell.rows.empty() ||
candidate.shell.physical_strain_energy != 0.0 ||
candidate.shell.equilibrium != zero_equilibrium ||
candidate.shell.verification_metrics != zero_metrics;
candidate.shell.verification_metrics != zero_metrics ||
candidate.shell.mitc4_drilling.has_value();
const bool has_complete_shell_inventory =
!candidate.expected_shell_elements.empty() &&
!candidate.shell.rows.empty();
@@ -10,6 +10,7 @@
#include <vector>
#include "fesa/math/vector3.h"
#include "results/mitc4_drilling_evidence.h"
namespace fesa::results_internal {
namespace {
@@ -243,11 +244,24 @@ Status RecoverShellGlobalEvidence(const Domain& domain, const DofManager& dofs,
candidate.shell.equilibrium[component] = force_balance[component];
candidate.shell.equilibrium[3U + component] = moment_balance[component];
}
Vector3 acceptance_moment = moment_balance;
if (candidate.shell.mitc4_drilling) {
CompleteDrillingEvidence(candidate.shell.equilibrium,
&*candidate.shell.mitc4_drilling);
if (!ValidDrillingEvidence(candidate.shell.mitc4_drilling,
candidate.shell.equilibrium))
return RecoveryFailure("invalid-shell-drilling-evidence",
{domain.SourcePath(), 0U}, "global-equilibrium",
"Shell drilling diagnostics must be finite and consistent.");
if (candidate.shell.mitc4_drilling->mode == Mitc4DrillingMode::kDirectSpring)
acceptance_moment = moment_balance -
Vector3(candidate.shell.mitc4_drilling->drilling_moment);
}
const double force_metric =
NormalizedBalance(force_balance.Components(),
(std::max)(applied_force_scale, reaction_force_scale));
const double moment_metric = NormalizedBalance(
moment_balance.Components(),
acceptance_moment.Components(),
(std::max)(applied_moment_scale, reaction_moment_scale));
candidate.shell.verification_metrics = {global.normalized_free_residual,
force_metric, moment_metric};
@@ -0,0 +1,54 @@
#ifndef FESA_RESULTS_MITC4_DRILLING_EVIDENCE_H_
#define FESA_RESULTS_MITC4_DRILLING_EVIDENCE_H_
#include <array>
#include <cmath>
#include <cstddef>
#include <optional>
#include "fesa/results/result_records.h"
namespace fesa::results_internal {
inline bool ValidDrillingMode(const Mitc4DrillingMode mode) {
return mode == Mitc4DrillingMode::kDirectSpring ||
mode == Mitc4DrillingMode::kLegacyCorotatedTwist;
}
/// @brief Validates exact raw-minus-internal diagnostics without a tolerance.
inline bool ValidDrillingEvidence(
const std::optional<Mitc4DrillingEvidence>& evidence,
const std::array<double, 6>& raw) {
if (!evidence) return true; // Older manually constructed fixtures.
if (!ValidDrillingMode(evidence->mode)) return false;
for (std::size_t i = 0U; i < 6U; ++i) {
const double expected = i < 3U ? raw[i]
: raw[i] - evidence->drilling_moment[i - 3U];
if (!std::isfinite(raw[i]) || !std::isfinite(expected) ||
!std::isfinite(evidence->equilibrium_with_drilling[i]) ||
evidence->equilibrium_with_drilling[i] != expected)
return false;
}
for (const double value : evidence->drilling_moment)
if (!std::isfinite(value)) return false;
return true;
}
inline bool SameDrillingInventory(
const std::optional<Mitc4DrillingEvidence>& left,
const std::optional<Mitc4DrillingEvidence>& right) {
return left.has_value() == right.has_value() &&
(!left || left->mode == right->mode);
}
/// @brief Keeps force balance raw and subtracts positive artificial moment once.
inline void CompleteDrillingEvidence(
const std::array<double, 6>& raw, Mitc4DrillingEvidence* evidence) {
evidence->equilibrium_with_drilling = raw;
for (std::size_t i = 0U; i < 3U; ++i)
evidence->equilibrium_with_drilling[3U + i] -= evidence->drilling_moment[i];
}
} // namespace fesa::results_internal
#endif // FESA_RESULTS_MITC4_DRILLING_EVIDENCE_H_
@@ -4,6 +4,8 @@
#include <cmath>
#include <cstddef>
#include "results/mitc4_drilling_evidence.h"
namespace fesa::results_internal {
bool IsFiniteShellRow(const ShellResultRow& row) {
@@ -29,6 +31,27 @@ Status ShellResultRecovery(const SourceLocation& location,
const EntityIndex expected_element,
const ShellElementResultRows& rows,
RecoveryCandidate& candidate) {
if ((rows.drilling_mode && !ValidDrillingMode(*rows.drilling_mode)) ||
!IsFiniteArray(rows.drilling_moment) ||
(candidate.has_shell_results &&
(candidate.shell.mitc4_drilling.has_value() != rows.drilling_mode.has_value() ||
(rows.drilling_mode &&
candidate.shell.mitc4_drilling->mode != *rows.drilling_mode)))) {
return RecoveryFailure("invalid-shell-drilling-evidence", location,
source_id.source_label_text,
"Shell recovery requires one finite actual drilling mode.");
}
if (rows.drilling_mode) {
if (!candidate.shell.mitc4_drilling)
candidate.shell.mitc4_drilling = Mitc4DrillingEvidence{*rows.drilling_mode};
for (std::size_t i = 0U; i < 3U; ++i) {
candidate.shell.mitc4_drilling->drilling_moment[i] += rows.drilling_moment[i];
if (!std::isfinite(candidate.shell.mitc4_drilling->drilling_moment[i]))
return RecoveryFailure("nonfinite-recovery-value", location,
source_id.source_label_text,
"Source-ordered drilling moment overflowed.");
}
}
const double accumulated_energy =
candidate.shell.physical_strain_energy + rows.physical_strain_energy;
if (!std::isfinite(rows.physical_strain_energy) ||