feat(linear-static-mitc4-shell): step 4 - mitc4-stiffness-drilling
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -213,6 +214,55 @@ Matrix scaledMatrix(const Matrix& source, double factor) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix congruence(const Matrix& local, const Matrix& transformation) {
|
||||
if (local.rows() != local.columns() ||
|
||||
local.rows() != transformation.rows()) {
|
||||
throw std::invalid_argument{"MITC4 congruence dimensions are incompatible."};
|
||||
}
|
||||
Matrix result{transformation.columns(), transformation.columns()};
|
||||
for (std::size_t row = 0U; row < result.rows(); ++row) {
|
||||
for (std::size_t column = row; column < result.columns(); ++column) {
|
||||
double value = 0.0;
|
||||
for (std::size_t localRow = 0U; localRow < local.rows(); ++localRow) {
|
||||
for (std::size_t localColumn = 0U;
|
||||
localColumn < local.columns(); ++localColumn) {
|
||||
value += transformation(localRow, row) *
|
||||
local(localRow, localColumn) *
|
||||
transformation(localColumn, column);
|
||||
}
|
||||
}
|
||||
result(row, column) = value;
|
||||
result(column, row) = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool isFinite(const Matrix& matrix) {
|
||||
for (std::size_t row = 0U; row < matrix.rows(); ++row) {
|
||||
for (std::size_t column = 0U; column < matrix.columns(); ++column) {
|
||||
if (!std::isfinite(matrix(row, column))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Result<Mitc4Stiffness> stiffnessFailure(
|
||||
const SourceLocation& location,
|
||||
const std::string& identity,
|
||||
std::string message) {
|
||||
return Result<Mitc4Stiffness>::failure(Status::failure(
|
||||
FailureCategory::model,
|
||||
{{Severity::error,
|
||||
"invalid-shell-stiffness",
|
||||
location,
|
||||
"*ELEMENT",
|
||||
identity,
|
||||
std::move(message)}}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result<Mitc4Shell> Mitc4Shell::create(
|
||||
@@ -302,7 +352,9 @@ Result<Mitc4Shell> Mitc4Shell::create(
|
||||
normalCandidate,
|
||||
section.thickness,
|
||||
material.youngsModulus,
|
||||
material.poissonRatio};
|
||||
material.poissonRatio,
|
||||
nodes[0]->location,
|
||||
identity};
|
||||
|
||||
const double shearModulus =
|
||||
material.youngsModulus / (2.0 * (1.0 + material.poissonRatio));
|
||||
@@ -519,6 +571,108 @@ Matrix Mitc4Shell::transverseShearSectionMatrix() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<Mitc4Stiffness> Mitc4Shell::stiffness() const {
|
||||
const Matrix constitutive = materialConstitutive5();
|
||||
const Matrix tyingSamples = covariantTyingShearSamples20();
|
||||
Matrix physicalLocal{kPhysicalDofCount, kPhysicalDofCount};
|
||||
for (const auto& point : volumeQuadrature()) {
|
||||
GeometryData geometry{};
|
||||
if (!evaluateGeometry(
|
||||
point.naturalCoordinates[0],
|
||||
point.naturalCoordinates[1],
|
||||
point.naturalCoordinates[2],
|
||||
geometry)) {
|
||||
return stiffnessFailure(
|
||||
sourceLocation_, identity_,
|
||||
"Validated MITC4 quadrature geometry became invalid.");
|
||||
}
|
||||
const Matrix strain = strainDisplacement(
|
||||
point.naturalCoordinates[0],
|
||||
point.naturalCoordinates[1],
|
||||
point.naturalCoordinates[2],
|
||||
&tyingSamples);
|
||||
for (std::size_t row = 0U; row < kPhysicalDofCount; ++row) {
|
||||
for (std::size_t column = row;
|
||||
column < kPhysicalDofCount; ++column) {
|
||||
double integrand = 0.0;
|
||||
for (std::size_t first = 0U; first < 5U; ++first) {
|
||||
for (std::size_t second = 0U; second < 5U; ++second) {
|
||||
integrand += strain(first, row) *
|
||||
constitutive(first, second) *
|
||||
strain(second, column);
|
||||
}
|
||||
}
|
||||
const double contribution =
|
||||
integrand * geometry.jacobian * point.weight;
|
||||
physicalLocal(row, column) += contribution;
|
||||
if (row != column) {
|
||||
physicalLocal(column, row) += contribution;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double drillingReference = (std::numeric_limits<double>::max)();
|
||||
bool hasDrillingReference = false;
|
||||
for (std::size_t node = 0U; node < kNodeCount; ++node) {
|
||||
const std::size_t offset = node * kPhysicalDofsPerNode;
|
||||
for (std::size_t rotation = 3U; rotation < 5U; ++rotation) {
|
||||
const double diagonal = physicalLocal(offset + rotation, offset + rotation);
|
||||
if (std::isfinite(diagonal) && diagonal > 0.0) {
|
||||
drillingReference = (std::min)(drillingReference, diagonal);
|
||||
hasDrillingReference = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasDrillingReference) {
|
||||
return stiffnessFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 drilling stabilization requires a finite positive physical "
|
||||
"tangent-rotation diagonal.");
|
||||
}
|
||||
if (!isFinite(physicalLocal)) {
|
||||
return stiffnessFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 physical stiffness must contain only finite values.");
|
||||
}
|
||||
|
||||
const double drillingStiffness = 1.0e-3 * drillingReference;
|
||||
if (!std::isfinite(drillingStiffness) || !(drillingStiffness > 0.0)) {
|
||||
return stiffnessFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 drilling stiffness must be finite and positive.");
|
||||
}
|
||||
|
||||
Matrix physicalGlobal = congruence(
|
||||
physicalLocal, physicalTransformation20());
|
||||
Matrix drillingLocal{kNodeCount, kNodeCount};
|
||||
for (std::size_t node = 0U; node < kNodeCount; ++node) {
|
||||
drillingLocal(node, node) = drillingStiffness;
|
||||
}
|
||||
Matrix drillingGlobal = congruence(
|
||||
drillingLocal, drillingTransformation4());
|
||||
Matrix stabilizedGlobal{kGlobalDofCount, kGlobalDofCount};
|
||||
for (std::size_t row = 0U; row < kGlobalDofCount; ++row) {
|
||||
for (std::size_t column = 0U; column < kGlobalDofCount; ++column) {
|
||||
stabilizedGlobal(row, column) =
|
||||
physicalGlobal(row, column) + drillingGlobal(row, column);
|
||||
}
|
||||
}
|
||||
if (!isFinite(physicalGlobal) || !isFinite(drillingGlobal) ||
|
||||
!isFinite(stabilizedGlobal)) {
|
||||
return stiffnessFailure(
|
||||
sourceLocation_, identity_,
|
||||
"MITC4 transformed stiffness must contain only finite values.");
|
||||
}
|
||||
|
||||
return Result<Mitc4Stiffness>::success(Mitc4Stiffness{
|
||||
std::move(physicalLocal),
|
||||
std::move(physicalGlobal),
|
||||
std::move(drillingGlobal),
|
||||
std::move(stabilizedGlobal),
|
||||
drillingStiffness});
|
||||
}
|
||||
|
||||
Mitc4Shell::Mitc4Shell(
|
||||
std::array<Vector3, 4> coordinates,
|
||||
std::array<Vector3, 4> directors,
|
||||
@@ -527,7 +681,9 @@ Mitc4Shell::Mitc4Shell(
|
||||
Vector3 normalCandidate,
|
||||
double thickness,
|
||||
double youngsModulus,
|
||||
double poissonRatio)
|
||||
double poissonRatio,
|
||||
SourceLocation sourceLocation,
|
||||
std::string identity)
|
||||
: coordinates_{std::move(coordinates)},
|
||||
directors_{std::move(directors)},
|
||||
tangentA_{std::move(tangentA)},
|
||||
@@ -535,7 +691,9 @@ Mitc4Shell::Mitc4Shell(
|
||||
normalCandidate_{std::move(normalCandidate)},
|
||||
thickness_{thickness},
|
||||
youngsModulus_{youngsModulus},
|
||||
poissonRatio_{poissonRatio} {}
|
||||
poissonRatio_{poissonRatio},
|
||||
sourceLocation_{std::move(sourceLocation)},
|
||||
identity_{std::move(identity)} {}
|
||||
|
||||
bool Mitc4Shell::evaluateGeometry(
|
||||
double xi,
|
||||
|
||||
Reference in New Issue
Block a user