Rで有限要素法:片持ち梁-全スパン等分布荷重:たわみ量

本ポストはこちらの続きです。

Rで有限要素法:片持ち梁-自由端集中荷重:たわみ量
const typesetMath = (el) => { if (window.MathJax) { // MathJax Typeset window.MathJax.typeset(); } else if (window.katex...

片持ち梁-全スパン等分布荷重

Figure 1: 片持ち梁-全スパン等分布荷重

片持ち梁のたわみ:FEM(オイラー・ベルヌーイ梁要素) vs 厳密解

# ============================================================
# 片持ち梁のたわみ(等分布荷重):FEM(オイラー・ベルヌーイ梁要素) vs 厳密解
# ============================================================
#
# 厳密解 (x は自由端Aから測った距離):
#   w(x)  = (p l^4)/(24EI) * { 3 - 4(x/l) + (x/l)^4 }
#   w_max = (p l^4)/(8EI)          [x = 0, 自由端]
#   θ(x)  = (p l^3)/(6EI) * { 1 - (x/l)^3 }
#   θ_A   = (p l^3)/(6EI)          [x = 0, 自由端]
#
# 集中荷重との違い:
#   厳密解が4次式になる(集中荷重のときは3次式)。
#   梁要素の近似関数(3次エルミート補間)では4次式を完全には表現できないため、
#   節点では厳密解と一致するが、要素内部にはごくわずかな誤差が生じる。
#
# 変数定義:
#   l   : 梁の長さ [m]
#   p   : 等分布荷重の強さ [N/m]
#   E   : ヤング率 [Pa]
#   I   : 断面二次モーメント [m^4]
#   EI  : 曲げ剛性
#   s   : FEM座標(固定端起点)、x = l - s で厳密解の座標に変換

library(ggplot2)

# ------------------------------------------------------------
# 1. 梁の諸元と荷重の設定
# ------------------------------------------------------------
l <- 2.0
p <- 500 # 等分布荷重 [N/m]
E <- 210e9
I <- 4.1667e-6
EI <- E * I

# ------------------------------------------------------------
# 2. 梁要素の剛性行列と等価節点荷重ベクトル
# ------------------------------------------------------------
# 等分布荷重 q をエルミート形状関数で重み付けして積分すると、
# 「等価節点荷重」として次の形が得られる(節点自由度順 [w1,θ1,w2,θ2]):
#   f_e = q * Le * [ 1/2,  Le/12,  1/2,  -Le/12 ]

beam_element_k <- function(Le) {
  (EI / Le^3) * matrix(c(
    12, 6 * Le, -12, 6 * Le,
    6 * Le, 4 * Le^2, -6 * Le, 2 * Le^2,
    -12, -6 * Le, 12, -6 * Le,
    6 * Le, 2 * Le^2, -6 * Le, 4 * Le^2
  ), nrow = 4, byrow = TRUE)
}

beam_element_f <- function(Le, q) {
  q * Le * c(1 / 2, Le / 12, 1 / 2, -Le / 12)
}

# ------------------------------------------------------------
# 3. メッシュ生成と全体行列への組み込み
# ------------------------------------------------------------
n_elem <- 4L
Le <- l / n_elem
n_node <- n_elem + 1L
n_dof <- 2L * n_node

K <- matrix(0, n_dof, n_dof)
F <- numeric(n_dof)
K_e <- beam_element_k(Le)
f_e <- beam_element_f(Le, p)

for (e in seq_len(n_elem)) {
  dofs <- c(2 * e - 1, 2 * e, 2 * e + 1, 2 * e + 2)
  K[dofs, dofs] <- K[dofs, dofs] + K_e
  F[dofs] <- F[dofs] + f_e
}

# ------------------------------------------------------------
# 4. 境界条件(固定端: w=0, θ=0。自由端に集中荷重はなし)
# ------------------------------------------------------------
fixed_dofs <- c(1, 2)
free_dofs <- setdiff(seq_len(n_dof), fixed_dofs)

u <- numeric(n_dof)
u[free_dofs] <- solve(K[free_dofs, free_dofs], F[free_dofs])

w_fem <- u[seq(1, n_dof, by = 2)]
th_fem <- u[seq(2, n_dof, by = 2)]

s_nodes <- seq(0, l, length.out = n_node)
x_nodes <- l - s_nodes

# ------------------------------------------------------------
# 5. 厳密解と節点値の比較
# ------------------------------------------------------------
w_exact_fn <- function(x) (p * l^4) / (24 * EI) * (3 - 4 * (x / l) + (x / l)^4)

comparison <- data.frame(
  自由端起点_x_m = round(x_nodes, 3),
  FEM近似解_mm = round(w_fem * 1000, 8),
  厳密解_mm = round(w_exact_fn(x_nodes) * 1000, 8),
_mm = w_fem * 1000 - w_exact_fn(x_nodes) * 1000
)
print(comparison)

cat("\n自由端でのたわみ量:\n")
cat("  FEM近似解:", w_fem[n_node] * 1000, "mm\n")
cat("  厳密解    :", p * l^4 / (8 * EI) * 1000, "mm  (公式: w_max = p l^4 / 8EI)\n")

# ------------------------------------------------------------
# 6. 要素内部を含めた比較(3次エルミート補間 vs 4次の厳密解)
#    ここで、節点では一致するが要素内部でわずかにずれることを確認する
# ------------------------------------------------------------
hermite_w <- function(xi, Le, w1, th1, w2, th2) {
  N1 <- 1 - 3 * xi^2 + 2 * xi^3
  N2 <- Le * (xi - 2 * xi^2 + xi^3)
  N3 <- 3 * xi^2 - 2 * xi^3
  N4 <- Le * (-xi^2 + xi^3)
  N1 * w1 + N2 * th1 + N3 * w2 + N4 * th2
}

fem_curve <- do.call(rbind, lapply(seq_len(n_elem), function(e) {
  xi_seq <- seq(0, 1, length.out = 20)
  w1 <- w_fem[e]
  th1 <- th_fem[e]
  w2 <- w_fem[e + 1]
  th2 <- th_fem[e + 1]
  s_local <- s_nodes[e] + xi_seq * Le
  data.frame(x = l - s_local, w_mm = hermite_w(xi_seq, Le, w1, th1, w2, th2) * 1000)
}))

x_fine <- seq(0, l, length.out = 300)
exact_curve <- data.frame(x = x_fine, w_mm = w_exact_fn(x_fine) * 1000)

# 要素内部での差(誤差)も別途プロットする
fem_curve$w_exact_mm <- w_exact_fn(fem_curve$x) * 1000
fem_curve$diff_um <- (fem_curve$w_mm - fem_curve$w_exact_mm) * 1000 # マイクロメートル単位

p1 <- ggplot() +
  geom_line(data = exact_curve, aes(x = x, y = w_mm, color = "厳密解"), linewidth = 1.2) +
  geom_line(
    data = fem_curve, aes(x = x, y = w_mm, color = "FEM(要素内補間)"),
    linetype = "dashed", linewidth = 0.8
  ) +
  geom_point(
    data = data.frame(x = x_nodes, w_mm = w_fem * 1000),
    aes(x = x, y = w_mm, color = "FEM(節点)"), size = 2
  ) +
  scale_color_manual(values = c(
    "厳密解" = "gray40", "FEM(要素内補間)" = "steelblue",
    "FEM(節点)" = "firebrick"
  ), name = "") +
  labs(
    title = "等分布荷重を受ける片持ち梁のたわみ曲線:FEM vs 厳密解",
    subtitle = paste0("要素数 = ", n_elem, "(節点では一致、要素内部にごくわずかな差)"),
    x = "自由端からの距離 x [m]", y = "たわみ量 w [mm]"
  ) +
  theme_minimal(base_size = 12)

p2 <- ggplot(fem_curve, aes(x = x, y = diff_um)) +
  geom_line(color = "darkred") +
  geom_hline(yintercept = 0, linetype = "dotted") +
  labs(
    title = "要素内部での誤差(FEM補間 - 厳密解)",
    x = "自由端からの距離 x [m]", y = "差 [μm](マイクロメートル)"
  ) +
  theme_minimal(base_size = 12)

print(p1)
print(p2)
  自由端起点_x_m FEM近似解_mm 厳密解_mm         差_mm
1            2.0    0.0000000 0.0000000  0.000000e+00
2            1.5    0.1205347 0.1205347  8.326673e-17
3            1.0    0.4047587 0.4047587  0.000000e+00
4            0.5    0.7633868 0.7633868 -2.220446e-16
5            0.0    1.1428480 1.1428480 -2.220446e-16

自由端でのたわみ量:
  FEM近似解: 1.142848 mm
  厳密解    : 1.142848 mm  (公式: w_max = p l^4 / 8EI)
Figure 2
Figure 3

Figure 2 および両者の比較(comparison)から、節点での差はすべて \(10^{-16}\) 台ですので、等分布荷重(厳密解が4次式)であっても、節点上ではFEMが厳密解と一致するという「等価節点荷重」の性質が確認できます。

Figure 3 の 要素内部の誤差を確認しますと、4つの要素それぞれに対応する、山が4つ並んだ波形になっています。各山の両端(節点の位置)でちょうど0になり、要素の中央付近で誤差が最大になる、という形が要素ごとに繰り返されています。

厳密解が4次式で、FEMの補間関数(3次エルミート補間)は3次式までしか表せないため、その差(誤差)は「4次の項」だけから生じます。

今回の厳密解は \(x\) について単一の4次多項式ですので、4階微分(4次の項の係数に対応する量)はどこでも一定です。

しかも各要素の幅(0.5m)がすべて同じですので、「要素内での誤差の最大値」は理論上、どの要素でも同じ値になります(誤差の大きさは要素幅の4乗にほぼ比例するため)。

なお、誤差大きさそのものは 0.09 μm(=0.00009 mm)程度 と、実務上は完全に無視できるレベルです。

この誤差は要素数を増やす(要素幅を小さくする)ことでさらに小さくでき、要素幅を半分にすれば理論上 \(2^4=16\) 分の1程度まで縮小します。

以上です。