feat(linear-static-mitc4-shell): step 5 - mitc4-physical-recovery
This commit is contained in:
@@ -249,6 +249,15 @@ bool isFinite(const Matrix& matrix) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isFinite(const Vector& vector) {
|
||||
for (std::size_t index = 0U; index < vector.size(); ++index) {
|
||||
if (!std::isfinite(vector[index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Result<Mitc4Stiffness> stiffnessFailure(
|
||||
const SourceLocation& location,
|
||||
const std::string& identity,
|
||||
@@ -263,6 +272,20 @@ Result<Mitc4Stiffness> stiffnessFailure(
|
||||
std::move(message)}}));
|
||||
}
|
||||
|
||||
Result<Mitc4PhysicalRecovery> recoveryFailure(
|
||||
const SourceLocation& location,
|
||||
const std::string& identity,
|
||||
std::string message) {
|
||||
return Result<Mitc4PhysicalRecovery>::failure(Status::failure(
|
||||
FailureCategory::model,
|
||||
{{Severity::error,
|
||||
"invalid-shell-recovery",
|
||||
location,
|
||||
"*ELEMENT",
|
||||
identity,
|
||||
std::move(message)}}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result<Mitc4Shell> Mitc4Shell::create(
|
||||
@@ -673,6 +696,132 @@ Result<Mitc4Stiffness> Mitc4Shell::stiffness() const {
|
||||
drillingStiffness});
|
||||
}
|
||||
|
||||
Result<Mitc4PhysicalRecovery> Mitc4Shell::recoverPhysical(
|
||||
const Vector& globalElementDisplacement24) const {
|
||||
if (globalElementDisplacement24.size() != kGlobalDofCount) {
|
||||
return recoveryFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 physical recovery requires exactly 24 global element DOFs.");
|
||||
}
|
||||
if (!isFinite(globalElementDisplacement24)) {
|
||||
return recoveryFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 physical recovery displacement must be finite.");
|
||||
}
|
||||
|
||||
const Vector physicalDisplacement =
|
||||
physicalTransformation20().multiply(globalElementDisplacement24);
|
||||
const Matrix tyingSamples = covariantTyingShearSamples20();
|
||||
const Matrix constitutive = materialConstitutive5();
|
||||
const Matrix planeStress = planeStressConstitutive();
|
||||
const double gauss = 1.0 / std::sqrt(3.0);
|
||||
const std::array<std::array<double, 2>, 4> surfacePoints{
|
||||
std::array<double, 2>{-gauss, -gauss},
|
||||
std::array<double, 2>{gauss, -gauss},
|
||||
std::array<double, 2>{gauss, gauss},
|
||||
std::array<double, 2>{-gauss, gauss}};
|
||||
constexpr std::array<double, 2> thicknessPoints{-1.0, 1.0};
|
||||
constexpr std::array<double, 3> sectionPositions{-1.0, 0.0, 1.0};
|
||||
|
||||
Mitc4PhysicalRecovery recovery{};
|
||||
for (std::size_t surface = 0U; surface < surfacePoints.size(); ++surface) {
|
||||
auto& point = recovery.points[surface];
|
||||
point.naturalCoordinates = surfacePoints[surface];
|
||||
GeometryData midsurfaceGeometry{};
|
||||
if (!evaluateGeometry(
|
||||
point.naturalCoordinates[0], point.naturalCoordinates[1], 0.0,
|
||||
midsurfaceGeometry)) {
|
||||
return recoveryFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 midsurface recovery geometry is invalid.");
|
||||
}
|
||||
point.localFrame = midsurfaceGeometry.frame;
|
||||
|
||||
for (double thicknessSign : thicknessPoints) {
|
||||
const double zeta = thicknessSign * gauss;
|
||||
const Matrix strainMatrix = strainDisplacement(
|
||||
point.naturalCoordinates[0], point.naturalCoordinates[1], zeta,
|
||||
&tyingSamples);
|
||||
const Vector strain = strainMatrix.multiply(physicalDisplacement);
|
||||
const Vector stress = constitutive.multiply(strain);
|
||||
GeometryData geometry{};
|
||||
if (!evaluateGeometry(
|
||||
point.naturalCoordinates[0], point.naturalCoordinates[1],
|
||||
zeta, geometry)) {
|
||||
return recoveryFailure(
|
||||
sourceLocation_, identity_,
|
||||
"Validated MITC4 recovery geometry became invalid.");
|
||||
}
|
||||
|
||||
for (std::size_t component = 0U; component < 3U; ++component) {
|
||||
point.generalizedStrain[component] += 0.5 * strain[component];
|
||||
point.generalizedStrain[3U + component] +=
|
||||
3.0 * zeta * strain[component] / thickness_;
|
||||
point.sectionResultant[component] +=
|
||||
0.5 * thickness_ * stress[component];
|
||||
point.sectionResultant[3U + component] +=
|
||||
0.25 * thickness_ * thickness_ * zeta * stress[component];
|
||||
}
|
||||
for (std::size_t component = 0U; component < 2U; ++component) {
|
||||
point.generalizedStrain[6U + component] +=
|
||||
0.5 * strain[3U + component];
|
||||
point.sectionResultant[6U + component] +=
|
||||
0.5 * thickness_ * stress[3U + component];
|
||||
}
|
||||
recovery.strainEnergy +=
|
||||
0.5 * strain.dot(stress) * geometry.jacobian;
|
||||
}
|
||||
|
||||
for (std::size_t position = 0U;
|
||||
position < sectionPositions.size(); ++position) {
|
||||
GeometryData sectionGeometry{};
|
||||
if (!evaluateGeometry(
|
||||
point.naturalCoordinates[0], point.naturalCoordinates[1],
|
||||
sectionPositions[position], sectionGeometry)) {
|
||||
return recoveryFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 section-position recovery geometry is invalid.");
|
||||
}
|
||||
const Vector strain = strainDisplacement(
|
||||
point.naturalCoordinates[0], point.naturalCoordinates[1],
|
||||
sectionPositions[position], &tyingSamples)
|
||||
.multiply(physicalDisplacement);
|
||||
Vector inPlaneStrain{3U};
|
||||
for (std::size_t component = 0U; component < 3U; ++component) {
|
||||
inPlaneStrain[component] = strain[component];
|
||||
}
|
||||
const Vector stress = planeStress.multiply(inPlaneStrain);
|
||||
for (std::size_t component = 0U; component < 3U; ++component) {
|
||||
point.inPlaneStress[position][component] = stress[component];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::isfinite(recovery.strainEnergy)) {
|
||||
return recoveryFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 physical strain energy must be finite.");
|
||||
}
|
||||
for (const auto& point : recovery.points) {
|
||||
const auto finite = [](const auto& values) {
|
||||
return std::all_of(values.begin(), values.end(), [](double value) {
|
||||
return std::isfinite(value);
|
||||
});
|
||||
};
|
||||
if (!finite(point.generalizedStrain) ||
|
||||
!finite(point.sectionResultant) ||
|
||||
std::any_of(
|
||||
point.inPlaneStress.begin(), point.inPlaneStress.end(),
|
||||
[&finite](const auto& stress) { return !finite(stress); })) {
|
||||
return recoveryFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 physical recovery values must be finite.");
|
||||
}
|
||||
}
|
||||
|
||||
return Result<Mitc4PhysicalRecovery>::success(std::move(recovery));
|
||||
}
|
||||
|
||||
Mitc4Shell::Mitc4Shell(
|
||||
std::array<Vector3, 4> coordinates,
|
||||
std::array<Vector3, 4> directors,
|
||||
|
||||
Reference in New Issue
Block a user