Files
2026-09-01 10:00:04 +03:00

116 lines
3.1 KiB
C++

#pragma once
// Axisymmetric finite-element integration kernels.
#include <array>
#include <cmath>
#include "Elasticity.h"
namespace fem_axisymmetric {
constexpr double kTwoPi = 6.28318530717958647692;
struct TriangleQuadraturePoint {
double weight;
std::array<double, 3> phi;
};
inline const std::array<TriangleQuadraturePoint, 3> kTriangleQuadrature = { {
{ 1.0 / 3.0, { 1.0 / 6.0, 1.0 / 6.0, 2.0 / 3.0 } },
{ 1.0 / 3.0, { 1.0 / 6.0, 2.0 / 3.0, 1.0 / 6.0 } },
{ 1.0 / 3.0, { 2.0 / 3.0, 1.0 / 6.0, 1.0 / 6.0 } }
} };
inline double signed_double_area(const Point& p1, const Point& p2, const Point& p3) {
return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
}
inline void assemble(
Matrix& A,
std::vector<double>& F,
const std::vector<Point>& points,
const std::vector<Triangle>& triangles,
double,
double E,
double nu,
const vec_function& f) {
const double lambda = (E * nu) / ((1.0 + nu) * (1.0 - 2.0 * nu));
const double mu = E / (2.0 * (1.0 + nu));
const Matrix C({
{ lambda + 2.0 * mu, lambda, lambda, 0.0 },
{ lambda, lambda + 2.0 * mu, lambda, 0.0 },
{ lambda, lambda, lambda + 2.0 * mu, 0.0 },
{ 0.0, 0.0, 0.0, mu }
});
for (const Triangle& T : triangles) {
const Point& p1 = points[T.a];
const Point& p2 = points[T.b];
const Point& p3 = points[T.c];
const double two_area = signed_double_area(p1, p2, p3);
const double area = 0.5 * std::fabs(two_area);
const Matrix grad_phi({
{ (p2.y - p3.y) / two_area, (p3.x - p2.x) / two_area },
{ (p3.y - p1.y) / two_area, (p1.x - p3.x) / two_area },
{ (p1.y - p2.y) / two_area, (p2.x - p1.x) / two_area }
});
Matrix Ae(6ull);
std::vector<double> Fe(6, 0.0);
for (const auto& qp : kTriangleQuadrature) {
const Point q = qp.phi[0] * p1 + qp.phi[1] * p2 + qp.phi[2] * p3;
const double r_q = q.x;
Matrix B(4ull, 6ull);
for (size_t p = 0; p < 3; ++p) {
const double dphi_dr = grad_phi[p][0];
const double dphi_dz = grad_phi[p][1];
const double phi = qp.phi[p];
B[0][2 * p] = dphi_dr;
B[1][2 * p + 1] = dphi_dz;
B[2][2 * p] = phi / r_q;
B[3][2 * p] = dphi_dz;
B[3][2 * p + 1] = dphi_dr;
}
const Matrix stiffness_q = B.T().dot(C).dot(B);
const double weight = kTwoPi * area * qp.weight * r_q;
for (size_t i = 0; i < 6; ++i)
for (size_t j = 0; j < 6; ++j)
Ae[i][j] += weight * stiffness_q[i][j];
const Point body_force = f(q);
for (size_t p = 0; p < 3; ++p) {
const double shape_value = qp.phi[p];
Fe[2 * p] += weight * shape_value * body_force.x;
Fe[2 * p + 1] += weight * shape_value * body_force.y;
}
}
auto dof = [T](size_t i) -> size_t {
if (i == 0) return 2 * T.a;
if (i == 1) return 2 * T.a + 1;
if (i == 2) return 2 * T.b;
if (i == 3) return 2 * T.b + 1;
if (i == 4) return 2 * T.c;
return 2 * T.c + 1;
};
for (size_t i = 0; i < 6; ++i) {
F[dof(i)] += Fe[i];
for (size_t j = 0; j < 6; ++j)
A[dof(i)][dof(j)] += Ae[i][j];
}
}
}
inline double boundary_segment_weight(const Point& midpoint, double len) {
return 0.5 * kTwoPi * midpoint.x * len;
}
} // namespace fem_axisymmetric