Rで有限要素法:等価節点荷重

本ポストではこちらのポストの https://www.saecanet.com/2026/09/finite-element-method-fem-in-r-cantilever-beam-with-a-partial-uniformly-distributed-load/

コード中の 3. 等価節点荷重をガウス求積で数値的に計算する(5点ガウス求積) パートのコード各行の意味と、変数 f_e で表せられた 等価節点荷重 について確認します。

# ------------------------------------------------------------
# 1. 梁の諸元と荷重の設定
# ------------------------------------------------------------
l <- 2.0
a <- 0.4
b <- 0.8
c <- l - a - b # 区間③の長さ(自動計算)
p <- 600 # 荷重区間での分布荷重の強さ [N/m]
E <- 210e9
I <- 4.1667e-6
EI <- E * I

# 荷重区間のFEM座標(固定端起点)での範囲
s_load_lo <- l - (a + b) # = c
s_load_hi <- l - a # = b + c

# 分布荷重をFEM座標sの関数として定義。区間[s_load_lo, s_load_hi]でのみp、他は0。
q_dist <- function(s) ifelse(s >= s_load_lo & s <= s_load_hi, p, 0)

# ------------------------------------------------------------
# 2. 形状関数と要素剛性行列
# ------------------------------------------------------------
shape_N <- function(xi, Le) {
  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)
  c(N1, N2, N3, N4)
}

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)
}

# ------------------------------------------------------------
# 3. 等価節点荷重をガウス求積で数値的に計算する(5点ガウス求積)
# ------------------------------------------------------------
gauss_pts <- c(
  0,
  -1 / 3 * sqrt(5 - 2 * sqrt(10 / 7)),
  1 / 3 * sqrt(5 - 2 * sqrt(10 / 7)),
  -1 / 3 * sqrt(5 + 2 * sqrt(10 / 7)),
  1 / 3 * sqrt(5 + 2 * sqrt(10 / 7))
)
gauss_wts <- c(
  128 / 225,
  (322 + 13 * sqrt(70)) / 900,
  (322 + 13 * sqrt(70)) / 900,
  (322 - 13 * sqrt(70)) / 900,
  (322 - 13 * sqrt(70)) / 900
)

beam_element_f <- function(s0, Le) {
  f_e <- numeric(4)
  for (k in seq_along(gauss_pts)) {
    xi <- (gauss_pts[k] + 1) / 2
    jac <- Le / 2
    s <- s0 + xi * Le
    q <- q_dist(s)
    f_e <- f_e + shape_N(xi, Le) * q * jac * gauss_wts[k]
  }
  f_e
}

# ------------------------------------------------------------
# 4. メッシュ生成(荷重区間の境界にちょうど節点が来るように要素数を選ぶ)
# ------------------------------------------------------------
n_elem <- 10L # Le=0.2、s_load_lo=0.8, s_load_hi=1.6 はともにLeの倍数
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)

for (e in seq_len(n_elem)) {
  s0 <- (e - 1) * Le
  f_e <- beam_element_f(s0, Le)
  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
}

コード各行の解説

gauss_pts <- c(
  0,
  -1 / 3 * sqrt(5 - 2 * sqrt(10 / 7)),
  1 / 3 * sqrt(5 - 2 * sqrt(10 / 7)),
  -1 / 3 * sqrt(5 + 2 * sqrt(10 / 7)),
  1 / 3 * sqrt(5 + 2 * sqrt(10 / 7))
)
# 5点ガウス求積で使う「評価点(サンプリング点)」の座標を定義する。
# これらは区間[-1, 1]上で、積分を最も効率よく(少ない点数で高い精度で)
# 近似できるように決められた、あらかじめ決まった5つの値

gauss_wts <- c(
  128 / 225,
  (322 + 13 * sqrt(70)) / 900,
  (322 + 13 * sqrt(70)) / 900,
  (322 - 13 * sqrt(70)) / 900,
  (322 - 13 * sqrt(70)) / 900
)
# 上記5つの評価点それぞれに対応する「重み」を定義する。
# 各点での関数の値を、この重みをかけてから足し合わせることで、積分の近似値が得られる。
# gauss_ptsと同じ順番で対応している(1番目の点には1番目の重み、というように)

beam_element_f <- function(s0, Le) {
  # 要素の等価節点荷重ベクトル(4成分)を計算する関数を定義する。
  # 引数s0はその要素の始点(固定端起点のFEM座標)、Leは要素の長さ

  f_e <- numeric(4)
  # 計算結果を格納する変数を、4つのゼロで用意する(4自由度分)

  for (k in seq_along(gauss_pts)) {
    # 5つの評価点それぞれについて、以下の計算を繰り返す(k=1〜5)

    xi <- (gauss_pts[k] + 1) / 2
    # ガウス求積の評価点は区間[-1,1]で定義されているが、
    # 形状関数shape_Nは区間[0,1]のξで定義されているため、座標を変換する

    jac <- Le / 2
    # 積分区間を変換したことによる「幅の比率の補正値」(ヤコビアン)。
    # ガウス求積の重みgauss_wtsは、幅2の区間[-1,1]を前提に定められているため、
    # そのまま使うと積分区間の幅の違いの分だけ値がずれてしまう。
    # 実際の積分区間の幅(Le)と、ガウス求積が前提とする幅(2)の比 Le/2 を掛けることで、
    # 正しい大きさの積分値になるよう補正する

    s <- s0 + xi * Le
    # 要素内のローカル座標xiを、梁全体でのFEM座標s(固定端起点)に変換する。
    # これにより、q_dist(s)でこの評価点の位置における実際の荷重の強さを求められる

    q <- q_dist(s)
    # その評価点の位置sにおける、分布荷重の強さを求める
    # (このケースでは、荷重区間内ならp、区間外なら0が返る)

    f_e <- f_e + shape_N(xi, Le) * q * jac * gauss_wts[k]
    # この評価点での「形状関数の値 × 荷重の強さ × ヤコビアン × 重み」を計算し、
    # これまでの合計に加算していく。5点分を繰り返し足し合わせることで、
    # 「形状関数×荷重」の積分(=等価節点荷重)が近似的に求まる
  }
  f_e
  # 5点分の計算が終わったら、最終的な等価節点荷重ベクトル(4成分)を返す
}

等価節点荷重の確認

n_elem <- 10L # Le=0.2、s_load_lo=0.8, s_load_hi=1.6 はともにLeの倍数
Le <- l / n_elem

for (e in seq_len(n_elem)) {
  s0 <- (e - 1) * Le
  f_e <- beam_element_f(s0, Le)
  print(f_e)
}
[1] 0 0 0 0
[1] 0 0 0 0
[1] 0 0 0 0
[1] 0 0 0 0
[1] 60  2 60 -2
[1] 60  2 60 -2
[1] 60  2 60 -2
[1] 60  2 60 -2
[1] 0 0 0 0
[1] 0 0 0 0

要素ごとの区間

n_elem <- 10l <- 2.0 ですので Le = 0.2。各要素 e の範囲は s0 から s0+Le までで、次のようになります。

要素番号s の範囲荷重区間[0.8, 1.6]との関係
1〜40.0〜0.8完全に区間外
5〜80.8〜1.6完全に区間内
9〜101.6〜2.0完全に区間外

要素1〜4、9〜10:[0 0 0 0]

これらの要素は荷重区間 [0.8, 1.6] に一切かかっていないため、その区間内でのガウス求積点はすべて q_dist(s) = 0 を返します。

したがって、形状関数に何を掛けても結果はゼロになり、等価節点荷重もすべてゼロになります。

要素5〜8:[60 2 60 -2]

これらの要素は、荷重区間に収まっているため、要素全体にわたって一様に p=600 の荷重がかかります。

これは、

\[f_e = p \cdot L_e \left[\frac{1}{2},\ \frac{L_e}{12},\ \frac{1}{2},\ -\frac{L_e}{12}\right]\]

に、\(p=600\)\(L_e=0.2\) を代入した値と一致します。

\[f_e = 600 \times 0.2 \times \left[0.5,\ \frac{0.2}{12},\ 0.5,\ -\frac{0.2}{12}\right] = [60,\ 2,\ 60,\ -2]\]

さらに、4つの要素すべてで全く同じ値になっていることを確認できます。

これは、要素5〜8がいずれも「荷重区間の中に完全に収まった、同じ長さ(\(L_e=0.2\))・同じ荷重強さ(\(p=600\))の要素」であるため、要素が梁のどの位置にあるかにかかわらず、等価節点荷重の値は同じになる、という性質を表しています。

つまり、荷重の分布そのものが要素内で一様であれば、その要素が梁全体のどこにあっても、局所的な計算結果は変わりません。

補足

等価節点荷重とは

有限要素法では、力のつり合いを節点だけに対して考えます。

しかし実際の荷重は、分布荷重のように「梁のあらゆる場所に連続的にかかっている」ものも多く、そのままでは節点の方程式に組み込めません。

等価節点荷重とは、「梁の途中にかかっている実際の荷重(分布荷重や、節点上にない集中荷重)を、それと力学的に同じ働きをする、節点だけにかかる力・モーメントに置き換えたもの」です。

ここで「同じ」というのは、力の大きさの合計が同じ、という意味ではありません。

「実際の荷重が変形に対してする仕事(エネルギー)」と、「置き換えた節点荷重が同じ変形に対してする仕事」が、常に等しくなるように定めています(仮想仕事の原理)。

具体的には、実際の分布荷重 \(q(x)\) に対して、形状関数 \(N_i(x)\) を使い、

\[f_i = \int q(x)\,N_i(x)\,dx\]

として等価節点荷重の各成分を計算します。

上記コードでは beam_element_f 関数が担っている計算そのものです。

また、形状関数 \(N_i(x)\) は、「節点 \(i\) の自由度だけを動かしたときの、梁の変形の形」を表す関数です。

したがって形状関数を利用すれば、

\[f_i = \int q(x)\,N_i(x)\,dx\]

は、「分布荷重 \(q(x)\) が、節点 \(i\) を動かしたときの変形パターン \(N_i(x)\) に対してする仕事」を計算していることになります。

これを節点 \(i\) に集中する等価な力として置き換えれば、「その力が同じ変形パターンに対してする仕事」と一致する、ということになります。

4つの自由度すべてについてこの計算をすることで、実際の分布荷重がもたらす効果を、4つの節点荷重で過不足なく代替できます。

観点説明
何をしているか要素内部にかかる実際の荷重を、節点だけにかかる力・モーメントに変換する
何が「等価」か力の合計ではなく、変形に対してする仕事(エネルギー)が実際の荷重と一致すること
どう計算するか荷重 × 形状関数 を、要素の長さにわたって積分する(\(f_i = \int q(x) N_i(x)\,dx\))
なぜ必要か有限要素法の連立方程式は節点の自由度についてしか組み立てられないため

等価節点荷重の導出

分布荷重 \(q\) が要素全体に一様にかかっているときの等価節点荷重を、形状関数を使って導出します。

基本の式

等価節点荷重は、「荷重×形状関数」を要素の長さにわたって積分したものです。

\[f_i = \int_0^{L_e} q\,N_i(x)\,dx\]

\(q\) は一定値(要素内のどこでも同じ)ですので、積分の外に出せます。

座標をxからξに変換

\(x=L_e\xi\)(ξは0〜1)と変数変換すると、\(dx=L_e\,d\xi\) ですので、

\[f_i = q\,L_e\int_0^1 N_i(\xi)\,d\xi\]

4つの形状関数を、それぞれ積分

こちらの形状関数を利用します。

Rで有限要素法:梁要素の剛性行列
const typesetMath = (el) => { if (window.MathJax) { // MathJax Typeset window.MathJax.typeset(); } else if (window.katex...

\[N_1=1-3\xi^2+2\xi^3,\quad N_2=L_e(\xi-2\xi^2+\xi^3),\quad N_3=3\xi^2-2\xi^3,\quad N_4=L_e(-\xi^2+\xi^3)\]

\(N_1\) の積分

\[\int_0^1(1-3\xi^2+2\xi^3)\,d\xi=\Big[\xi-\xi^3+\tfrac{1}{2}\xi^4\Big]_0^1=1-1+\tfrac12=\tfrac12\]

\(N_2\) の積分

\[\int_0^1 L_e(\xi-2\xi^2+\xi^3)\,d\xi=L_e\Big[\tfrac12\xi^2-\tfrac23\xi^3+\tfrac14\xi^4\Big]_0^1=L_e\left(\tfrac12-\tfrac23+\tfrac14\right)=L_e\cdot\tfrac{1}{12}\]

\(N_3\) の積分

\[\int_0^1(3\xi^2-2\xi^3)\,d\xi=\Big[\xi^3-\tfrac12\xi^4\Big]_0^1=1-\tfrac12=\tfrac12\]

\(N_4\) の積分

\[\int_0^1 L_e(-\xi^2+\xi^3)\,d\xi=L_e\Big[-\tfrac13\xi^3+\tfrac14\xi^4\Big]_0^1=L_e\left(-\tfrac13+\tfrac14\right)=L_e\cdot\left(-\tfrac{1}{12}\right)\]

まとめ

4つの積分結果を、\(f_i=q\,L_e\displaystyle\int_0^1 N_i\,d\xi\) に代入しますと、

\[f_1=q\,L_e\cdot\frac12,\quad f_2=q\,L_e\cdot\frac{L_e}{12},\quad f_3=q\,L_e\cdot\frac12,\quad f_4=q\,L_e\cdot\left(-\frac{L_e}{12}\right)\]

したがって、

\[f_e = q\,L_e\left[\frac{1}{2},\ \frac{L_e}{12},\ \frac{1}{2},\ -\frac{L_e}{12}\right]\]

が得られます。

以上です。